zoukankan      html  css  js  c++  java
  • 用MediaRecorder实现简单的录像功能

    思路:定义一个SurfaceView用来显示预览,在SurfaceHolder的回调中用Camera对象启动预览。然后调用MediaRecorder来录像。仅仅是实现了简单的录像開始和停止功能。顶部能显示显示录像的时间,还有待完好。

    代码例如以下:

    在AndroidManifest.xml加入以下的权限:

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!-- 硬件支持 -->
    <uses-feature android:name="android.hardware.camera"/>
    <uses-feature android:name="android.hardware.camera.autofocus"/>
    activity_main.xml
    <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" >
    
        <SurfaceView
            android:id="@+id/camera_preview"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:orientation="horizontal">
    
            <TextView
                android:id="@+id/timestamp_minute_prefix"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#7F00FF"
                android:textSize="30sp"
                android:text="0"/>
    
            <TextView
                android:id="@+id/timestamp_minute_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#7F00FF"
                android:textSize="30sp"
                android:text="0"/>
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#7F00FF"
                android:textSize="30sp"
                android:text=":"/>
    
            <TextView
                android:id="@+id/timestamp_second_prefix"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#7F00FF"
                android:textSize="30sp"
                android:text="0"/>
    
            <TextView
                android:id="@+id/timestamp_second_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#7F00FF"
                android:textSize="30sp"
                android:text="0"/>
        </LinearLayout>
    
        <ImageButton
            android:id="@+id/record_shutter"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="15dp"
            android:background="@android:color/transparent"
            android:scaleType="centerCrop"
            android:src="@drawable/recording_shutter" />
    
    </RelativeLayout>
    MainActivity.java
    package com.jackie.videorecorder;
    
    import java.io.File;
    
    import android.app.Activity;
    import android.hardware.Camera;
    import android.hardware.Camera.Parameters;
    import android.hardware.Camera.Size;
    import android.media.MediaRecorder;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.Handler;
    import android.util.Log;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.ImageButton;
    import android.widget.TextView;
    
    import org.w3c.dom.Text;
    
    public class MainActivity extends Activity implements OnClickListener {
        private SurfaceView mCameraPreview;
        private SurfaceHolder mSurfaceHolder;
        private ImageButton mShutter;
        private TextView mMinutePrefix;
        private TextView mMinuteText;
        private TextView mSecondPrefix;
        private TextView mSecondText;
    
        private Camera mCamera;
        private MediaRecorder mRecorder;
    
        private final static int CAMERA_ID = 0;
    
        private boolean mIsRecording = false;
        private boolean mIsSufaceCreated = false;
    
        private static final String TAG = "Jackie";
    
        private Handler mHandler = new Handler();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mCameraPreview = (SurfaceView) findViewById(R.id.camera_preview);
            mMinutePrefix = (TextView) findViewById(R.id.timestamp_minute_prefix);
            mMinuteText = (TextView) findViewById(R.id.timestamp_minute_text);
            mSecondPrefix = (TextView) findViewById(R.id.timestamp_second_prefix);
            mSecondText = (TextView) findViewById(R.id.timestamp_second_text);
    
            mSurfaceHolder = mCameraPreview.getHolder();
            mSurfaceHolder.addCallback(mSurfaceCallback);
            mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
            mShutter = (ImageButton) findViewById(R.id.record_shutter);
            mShutter.setOnClickListener(this);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            if (mIsRecording) {
                stopRecording();
            }
            stopPreview();
        }
    
        private  SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                mIsSufaceCreated = false;
            }
    
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                mIsSufaceCreated = true;
            }
    
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                startPreview();
            }
        };
    
        //启动预览
        private void startPreview() {
            //保证仅仅有一个Camera对象
            if (mCamera != null || !mIsSufaceCreated) {
                Log.d(TAG, "startPreview will return");
                return;
            }
    
            mCamera = Camera.open(CAMERA_ID);
    
            Parameters parameters = mCamera.getParameters();
            Size size = getBestPreviewSize(CameraUtils.PREVIEW_WIDTH, CameraUtils.PREVIEW_HEIGHT, parameters);
            if (size != null) {
                parameters.setPreviewSize(size.width, size.height);
            }
    
            parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            parameters.setPreviewFrameRate(20);
    
            //设置相机预览方向
            mCamera.setDisplayOrientation(90);
    
            mCamera.setParameters(parameters);
    
            try {
                mCamera.setPreviewDisplay(mSurfaceHolder);
    //			mCamera.setPreviewCallback(mPreviewCallback);
            } catch (Exception e) {
                Log.d(TAG, e.getMessage());
            }
    
            mCamera.startPreview();
        }
    
        private void stopPreview() {
            //释放Camera对象
            if (mCamera != null) {
                try {
                    mCamera.setPreviewDisplay(null);
                } catch (Exception e) {
                    Log.e(TAG, e.getMessage());
                }
    
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
        }
    
        private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
            Camera.Size result = null;
    
            for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
                if (size.width <= width && size.height <= height) {
                    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;
        }
    
        @Override
        public void onClick(View v) {
            if (mIsRecording) {
                stopRecording();
            } else {
                initMediaRecorder();
                startRecording();
    
                //開始录像后,每隔1s去更新录像的时间戳
                mHandler.postDelayed(mTimestampRunnable, 1000);
            }
        }
    
        private void initMediaRecorder() {
            mRecorder = new MediaRecorder();//实例化
            mCamera.unlock();
            //给Recorder设置Camera对象,保证录像跟预览的方向保持一致
            mRecorder.setCamera(mCamera);
            mRecorder.setOrientationHint(90);  //改变保存后的视频文件播放时是否横屏(不加这句。视频文件播放的时候角度是反的)
            mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置从麦克风採集声音
            mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 设置从摄像头採集图像
            mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);  // 设置视频的输出格式 为MP4
            mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); // 设置音频的编码格式
            mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置视频的编码格式
            mRecorder.setVideoSize(176, 144);  // 设置视频大小
            mRecorder.setVideoFrameRate(20); // 设置帧率
    //        mRecorder.setMaxDuration(10000); //设置最大录像时间为10s
            mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
    
            //设置视频存储路径
            File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator + "VideoRecorder");
            if (!file.exists()) {
                //多级目录的创建
                file.mkdirs();
            }
            mRecorder.setOutputFile(file.getPath() + File.separator + "VID_" + System.currentTimeMillis() + ".mp4");
        }
    
        private void startRecording() {
            if (mRecorder != null) {
                try {
                    mRecorder.prepare();
                    mRecorder.start();
                } catch (Exception e) {
                    mIsRecording = false;
                    Log.e(TAG, e.getMessage());
                }
            }
    
            mShutter.setImageDrawable(getResources().getDrawable(R.drawable.recording_shutter_hl));
            mIsRecording = true;
        }
    
        private void stopRecording() {
            if (mCamera != null) {
                mCamera.lock();
            }
    
            if (mRecorder != null) {
                mRecorder.stop();
                mRecorder.release();
                mRecorder = null;
            }
    
            mShutter.setImageDrawable(getResources().getDrawable(R.drawable.recording_shutter));
            mIsRecording = false;
    
            mHandler.removeCallbacks(mTimestampRunnable);
    
            //将录像时间还原
            mMinutePrefix.setVisibility(View.VISIBLE);
            mMinuteText.setText("0");
            mSecondPrefix.setVisibility(View.VISIBLE);
            mSecondText.setText("0");
    
            //重新启动预览
            startPreview();
        }
    
        private Runnable mTimestampRunnable = new Runnable() {
            @Override
            public void run() {
                updateTimestamp();
                mHandler.postDelayed(this, 1000);
            }
        };
    
        private void updateTimestamp() {
            int second = Integer.parseInt(mSecondText.getText().toString());
            int minute = Integer.parseInt(mMinuteText.getText().toString());
            second++;
            Log.d(TAG, "second: " + second);
    
            if (second < 10) {
                mSecondText.setText(String.valueOf(second));
            } else if (second >= 10 && second < 60) {
                mSecondPrefix.setVisibility(View.GONE);
                mSecondText.setText(String.valueOf(second));
            } else if (second >= 60) {
                mSecondPrefix.setVisibility(View.VISIBLE);
                mSecondText.setText("0");
    
                minute++;
                mMinuteText.setText(String.valueOf(minute));
            } else if (minute >= 60) {
                mMinutePrefix.setVisibility(View.GONE);
            }
        }
    }

    效果例如以下:



  • 相关阅读:
    [转]移动端实现垂直居中的几种方法
    MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
    关于分布式计算的一些概念
    一份最中肯的Java学习路线+资源分享(拒绝傻逼式分享)
    Java多线程学习(八)线程池与Executor 框架
    深入理解工厂模式
    深入理解单例模式
    Java NIO 之 Buffer(缓冲区)
    Java NIO 概览
    分布式系统的经典基础理论
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7027608.html
Copyright © 2011-2022 走看看