首页 文章

如何在我的Android应用程序中录制视频 .

提问于
浏览
125

如何在Android上捕获视频录制?

10 回答

  • 5

    为了搜索者的利益,此示例将为您提供活动预览,并带有用于录制的开始/停止按钮 . 它是从这个android blog修改而来似乎相当可靠 .

    java class (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 (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>
    
  • 2

    这个演示对你有帮助....

    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>
    

    Your Main Activity: 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 Class

    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 (i.e., 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...
    }
    
  • 0

    这是一个调用捕获视频的意图的函数 .

    static final int REQUEST_VIDEO_CAPTURE = 1;
    
    private void dispatchTakeVideoIntent() {
        Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
        if (takeVideoIntent.resolveActivity(getPackageManager()) != null) {
            startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
        }
    }
    

    以下代码检索此视频并将其显示在VideoView中 .

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
            Uri videoUri = intent.getData();
            mVideoView.setVideoURI(videoUri);
        }
    }
    
  • 1

    以下是使用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();
        }
    }
    

    这是我的书:Pro Android Media: Developing Graphics, Music, Video, and Rich Media Apps for Smartphones and Tablets

    另外,不要忘记在清单中包含这些权限:

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • 3

    这是另一个有效的例子

    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" />
    
  • 154

    查看此示例相机预览代码,CameraPreview . 这将帮助您开发用于视频预览的视频录制代码,创建 MediaRecorder 对象以及设置视频录制参数 .

  • 42

    如果您使用后置摄像头,上述示例将起作用 . 如果您使用前置摄像头,则必须调整一些内容:

    首先,您需要在清单中添加新权限 .

    <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 是为后置摄像头预留的 .

    您还必须将mediarecorder的视频大小设置为在曲面视图中 .

    Here is the full example of recording video from front camera with a small preview display:

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

    截至2017年12月,已有一些更新,例如现在不推荐使用 android.hardware.Camera . 虽然较新的 android.hardware.camera2 带有方便的东西,如 CameraManager .

    我个人非常喜欢这个例子,它使用了这个当前的API并且像魅力一样:https://github.com/googlesamples/android-Camera2Video

    它还包括在开始视频录制之前询问用户启动时所需的权限以及功能视频预览 .

    (另外,我发现代码非常漂亮(这对我来说非常罕见^^),但这只是我的主观意见 . )

  • 5

    作为旁注 - Android API或错误的文档中似乎存在错误,或者我只是简单的愚蠢 . 谷歌文档明确指出以下内容:

    注意:从Android 4.0(API级别14)开始,将自动为您管理Camera.lock()和Camera.unlock()调用 .

    见:http://developer.android.com/guide/topics/media/camera.html

    This does not seem to be the case!

    在没有任何成功的情况下进行了很多日子的打击以及诸如“未能启动”之类的许多小问题,我决定手动实施锁定和BAM!一切正常 .

    我使用genymotion模拟器为4.1.1设备,最小sdk为14 .

  • 0

    您使用相同的MediaRecorder类录制音频和视频 . 它's pretty simple. Here'是example .

相关问题