使用MediaRecorder实现简单的录像功能


效果


代码

package com.javen.devicemange.CrazyOne.media;

import android.Manifest;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;

import com.javen.devicemange.R;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by Administrator on 2017/3/2 0002.
 * 使用MediaRecorder实现简单的录像功能
 */

public class MediaRecordVideo extends AppCompatActivity implements View.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 = "GsonUtils";

    private Handler mHandler = new Handler();
    private int width;
    private int height;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mediarecordvideo);
        //申请权限
        requestPermission();
        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);
        mShutter = (ImageButton) findViewById(R.id.record_shutter);
        Log.d(TAG, "mShutter=" + mShutter);

        /***1.定义一个SurfaceView用来显示预览***/
        mSurfaceHolder = mCameraPreview.getHolder();
        mSurfaceHolder.addCallback(mSurfaceCallback);
        // mSurfaceView 不需要自己的缓冲区
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        //获取SurfaceView的宽高
        width = mCameraPreview.getWidth();
        height = mCameraPreview.getHeight();
        Log.d("GsonUtils", "width=" + width);
        Log.d("GsonUtils", "height=" + height);
        mShutter.setOnClickListener(this);
    }

    /**
     * 申请权限
     */
    private void requestPermission() {
        String[] needPermission = {
                Manifest.permission.CAMERA,
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
        };
        ActivityCompat.requestPermissions(this, needPermission, 1);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mIsRecording) {
            //先停止记录
            stopRecording();
        }
        //停止预览
        stopPreview();
    }

    /***
     * 2.SurfaceHolder的回调中用Camera对象启动预览
     ***/
    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对象
        //mCamera存在的,或者mIsSufaceCreated还存在
        if (mCamera != null || !mIsSufaceCreated) {
            Log.d(TAG, "startPreview will return");
            return;
        }
        //打开相机
        mCamera = Camera.open(CAMERA_ID);

        Camera.Parameters parameters = mCamera.getParameters();
        //获取最佳的预览尺寸
        Camera.Size size = getBestPreviewSize(width, height, parameters);
        if (size != null) {
            //设置预览的尺寸
            parameters.setPreviewSize(size.width, size.height);
        }

        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        //设置视频每秒20        parameters.setPreviewFrameRate(20);

        //设置相机预览方向
        mCamera.setDisplayOrientation(90);

        mCamera.setParameters(parameters);

        try {
            //surfaceView来预览Camera
            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;
        }
    }

    /**
     * 获取最佳的预览尺寸
     *
     * @param width
     * @param height
     * @param parameters
     * @return
     */
    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 {
            /***3.然后调用MediaRecorder来录像***/
            initMediaRecorder();
            startRecording();

            //开始录像后,每隔1s去更新录像的时间戳,开启任务
            mHandler.postDelayed(mTimestampRunnable, 1000);
        }
    }

    /**
     * 初始化MediaRecorder
     */
    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());

        String videoPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator + "VideoRecorder".toString();
        Log.d("GsonUtils", "videoPath=" + videoPath);
        //设置视频存储路径sd卡:movies/VideoRecorder
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator + "VideoRecorder");
        if (!file.exists()) {
            //多级文件夹的创建
            file.mkdirs();
        }
        //获取到当前时间状态
        Date date = new Date();
        date.setTime(System.currentTimeMillis());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd_HH:mm");
        String currentTime = simpleDateFormat.format(date);
        Log.d("GsonUtils", "currentTime=" + currentTime);
        mRecorder.setOutputFile(file.getPath() + File.separator + "VID_" + currentTime + ".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.btn_radio_on));
        //标记为已经在记录中
        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.btn_radio_off_));
        mIsRecording = false;
        //移除runnable的任务
        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();
            //每隔1s开启runnable任务
            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) {
            //超过10s,隐藏十位上的秒。
            mSecondPrefix.setVisibility(View.GONE);
            mSecondText.setText(String.valueOf(second));
        } else if (second >= 60) {
            //超过60s,显示十位上的秒。
            mSecondPrefix.setVisibility(View.VISIBLE);
            mSecondText.setText("0");

            minute++;
            mMinuteText.setText(String.valueOf(minute));
        } else if (minute >= 10) {
            mMinutePrefix.setVisibility(View.GONE);
        }
    }
}

布局


AndroidManifest.xml

<!--授予程序相机,读写sd卡的权限-->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

<!--硬件支持-->
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>

。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值