Android 开发 MediaRecorder使用Camera1配合录制视频

前言

  MediaRecorder可以不依靠Camera API 实现视频的录制,但是如果需要切换摄像头/设置对焦/选择分辨率等等就需要Camera来参与配合录制视频.这篇博客将介绍使用Camera1来实现视频录制.此篇博客不在重复一些细节和坑的介绍.如果你刚接触建议你看我另一篇博客https://www.cnblogs.com/guanxinjing/p/10980906.html这篇博客用更简单易懂的形式说明了MediaRecorder录制视频的步骤,并且有大量深坑的详解介绍,防止你也掉坑里.

实现流程

  1.   设置TextureView的硬件加速
  2.   获取权限
  3.   初始化TextureView的监听
  4.   初始化MediaRecorder
  5.   初始化Camera
  6.   初始化配置Camera
  7.   开始相机预览
  8.   配置MediaRecorder(每次录制之前都需要配置一次)
  9.   开始录制
  10.   停止录制
  11.   恢复相机预览

代码部分

  关键点有大量注释,就不做另外篇幅的介绍

  如果你对下面代码里的计算分辨率不甚理解,可以去我另一篇博客有更详细的讲解分辨率的计算,这篇博客虽然是拿Camera2 API来计算分辨率,但是原理是一样的. 传送门:https://www.cnblogs.com/guanxinjing/p/10943966.html

  如果你对Camera自动对焦不太理解,可以去我另一篇更详细的博客有介绍Camera1的自动对焦. 传送门:https://www.cnblogs.com/guanxinjing/p/10986249.html

import androidx.appcompat.app.AppCompatActivity;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import java.io.File;
import java.io.IOException;
import java.util.List;

public class MedioRecorderCamera1Activity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = MedioRecorderCamera1Activity.class.getSimpleName();
    private TextureView mTextureview;
    private Button mBtnStart, mBtnFinish;
    private MediaRecorder mMediaRecorder;
    private Camera mCamera;
    private Camera.Size mSelectSize;//记录当前选择的分辨率
    private boolean isRecorder = false;//用于判断当前是否在录制视频
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0x01:
                    mCamera.autoFocus(new Camera.AutoFocusCallback() { //自动对焦
                        @Override
                        public void onAutoFocus(boolean success, Camera camera) {

                        }
                    });
                    mHandler.sendEmptyMessageDelayed(0x01,2*1000);//2秒之后在对焦一次,一直重复自动对焦
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_medio_recorder_camera1);
        mTextureview = findViewById(R.id.textureview);
        mBtnStart = findViewById(R.id.btn_start);
        mBtnFinish = findViewById(R.id.btn_finish);
        mBtnStart.setOnClickListener(this);
        mBtnFinish.setOnClickListener(this);
        initTextureViewListener();
        initMediaRecorder();

    }

    /**
     * 初始化TextureView监听
     */
    private void initTextureViewListener(){
        mTextureview.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { //Textureview初始化启用回调
                initCamera();
                initCameraConfig();
                try {
                    mCamera.setPreviewTexture(surface);
                    mCamera.startPreview();
                    mHandler.sendEmptyMessage(0x01);//启动对焦
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {

            }
        });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_start:
                startRecorder();

                break;
            case R.id.btn_finish:
                stopRecorder();

                break;
            default:
                break;
        }

    }

    /**
     * 初始化MediaRecorder
     */
    private void initMediaRecorder(){
        mMediaRecorder = new MediaRecorder();
    }

    /**
     * 选择摄像头
     * @param isFacing true=前摄像头 false=后摄像头
     * @return 摄像id
     */
    private Integer selectCamera(boolean isFacing){
        int cameraCount = Camera.getNumberOfCameras();
//        CameraInfo.CAMERA_FACING_BACK 后摄像头
//        CameraInfo.CAMERA_FACING_FRONT  前摄像头
        int facing = isFacing ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK;
        Log.e(TAG, "selectCamera: cameraCount="+cameraCount);
        if (cameraCount == 0){
            Log.e(TAG, "selectCamera: The device does not have a camera ");
            return null;
        }
        Camera.CameraInfo info = new Camera.CameraInfo();
        for (int i=0; i < cameraCount; i++){
            Camera.getCameraInfo(i,info);
            if (info.facing == facing){
                return i;
            }

        }
        return null;

    }

    /**
     * 初始化相机
     */
    private void initCamera(){
        mCamera = Camera.open(selectCamera(false));
        mSelectSize = selectPreviewSize(mCamera.getParameters());

    }

    /**
     * 初始化相机配置
     */
    private void initCameraConfig(){
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);//关闭闪光灯
        parameters.setFocusMode(Camera.Parameters.FLASH_MODE_AUTO); //对焦设置为自动
        parameters.setPreviewSize(mSelectSize.width,mSelectSize.height);//设置预览尺寸
        parameters.setPictureSize(mSelectSize.width,mSelectSize.height);//设置图片尺寸  就拿预览尺寸作为图片尺寸,其实他们基本上是一样的
        parameters.set("orientation", "portrait");//相片方向
        parameters.set("rotation", 90); //相片镜头角度转90度(默认摄像头是横拍)
        mCamera.setParameters(parameters);//添加参数
        mCamera.setDisplayOrientation(90);//设置显示方向

    }

    /**
     * 计算获取预览尺寸
     * @param parameters
     * @return
     */
    private Camera.Size selectPreviewSize(Camera.Parameters parameters){
        List<Camera.Size> previewSizeList =  parameters.getSupportedPreviewSizes();
        if (previewSizeList.size() == 0){
            Log.e(TAG, "selectPreviewSize: previewSizeList size is 0" );
            return null;

        }

        Camera.Size currentSelectSize = null;
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        int deviceWidth =displayMetrics.widthPixels;
        int deviceHeight = displayMetrics.heightPixels;
        for (int i = 1; i < 41 ; i++){
            for(Camera.Size itemSize : previewSizeList){
//                Log.e(TAG, "selectPreviewSize: itemSize 宽="+itemSize.width+"高"+itemSize.height);
                if (itemSize.height > (deviceWidth - i*5) && itemSize.height < (deviceWidth + i*5)){
                    if (currentSelectSize != null){ //如果之前已经找到一个匹配的宽度
                        if (Math.abs(deviceHeight-itemSize.width) < Math.abs(deviceHeight - currentSelectSize.width)){ //求绝对值算出最接近设备高度的尺寸
                            currentSelectSize = itemSize;
                            continue;
                        }
                    }else {
                        currentSelectSize = itemSize;
                    }

                }

            }
        }
        Log.e(TAG, "selectPreviewSize: 当前选择的尺寸 宽="+currentSelectSize.width+"高"+currentSelectSize.height);
        return currentSelectSize;
    }

    /**
     * 配置MedioRecorder
     */
    private void configMedioRecorder(){
        File saveRecorderFile = new File(getExternalCacheDir(),"CameraRecorder.mp4");
        if (saveRecorderFile.exists()){
            saveRecorderFile.delete();
        }
        mCamera.unlock();
        mMediaRecorder.setCamera(mCamera);
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);//设置音频源
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);//设置视频源
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);//设置音频输出格式
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//设置音频编码格式
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);//设置视频编码格式
        mMediaRecorder.setVideoSize(mSelectSize.width,mSelectSize.height);//设置视频分辨率
        mMediaRecorder.setVideoEncodingBitRate(8*1920*1080);//设置视频的比特率
        mMediaRecorder.setVideoFrameRate(60);//设置视频的帧率
        mMediaRecorder.setOrientationHint(90);//设置视频的角度
        mMediaRecorder.setMaxDuration(60*1000);//设置最大录制时间
        Surface surface = new Surface(mTextureview.getSurfaceTexture());
        mMediaRecorder.setPreviewDisplay(surface);//设置预览
        mMediaRecorder.setOutputFile(saveRecorderFile.getAbsolutePath());//设置文件保存路径
        mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() { //录制异常监听
            @Override
            public void onError(MediaRecorder mr, int what, int extra) {
                mMediaRecorder.stop();
                mMediaRecorder.reset();
                try {
                    mCamera.setPreviewTexture(mTextureview.getSurfaceTexture());
                    mCamera.startPreview();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        });

    }

    /**
     * 开启录制视频
     */
    private void startRecorder(){
        if (!isRecorder) {//如果不在录制视频
            mCamera.stopPreview();//暂停相机预览
            configMedioRecorder();//再次配置MedioRecorder
            try {
                mMediaRecorder.prepare();//准备录制
            } catch (IOException e) {
                e.printStackTrace();
            }
            mMediaRecorder.start();//开始录制
            isRecorder = true;
        }

    }

    /**
     * 停止录制视频
     */
    private void stopRecorder(){
        if (isRecorder){ //如果在录制视频
            mMediaRecorder.stop();//暂停录制
            mMediaRecorder.reset();//重置,将MediaRecorder调整为空闲状态
            isRecorder = false;
            try {
                mCamera.setPreviewTexture(mTextureview.getSurfaceTexture());//重新设置预览SurfaceTexture
                mCamera.startPreview(); //重新开启相机预览
                mCamera.autoFocus(new Camera.AutoFocusCallback() {
                    @Override
                    public void onAutoFocus(boolean success, Camera camera) {

                    }
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mMediaRecorder != null){
            if (isRecorder) {
                mMediaRecorder.stop();
            }
            mMediaRecorder.release();
            mMediaRecorder = null;
        }
        if (mCamera != null){
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;

        }
    }
}

原文地址:https://www.cnblogs.com/guanxinjing/p/10986766.html

时间: 2024-10-10 09:55:14

Android 开发 MediaRecorder使用Camera1配合录制视频的相关文章

Android切换前后置摄像头并录制视频

效果图: java代码: /** * RecordActivity.java * 版权所有(C) 2013 * 创建:cuiran 2013-10-15 下午3:20:45 */ package com.app931.oa.activity.video; import java.io.IOException; import java.util.List; import com.app931.oa.R; import com.app931.oa.util.LogsUtil; import com.

Android录制视频

我们一般直接从摄像头和麦克风取数据,经过编码,保存为文件.android的视频录制需要使用到MediaRecorder,MediaRecorder除了可以用于录制音频,还可用于录制视频. 效果图如下图所示: 一个为录制过程中,可以看到屏幕上方的录制时间显示,后一个为停止录制视频. 然后录制好的视频可以在手机的SD卡中找到,如下图所示: 视频录制步骤: 1) 调用MediaRecorder 对象的setVideoEncoder().setVideoEncodingBitRate(intbitRat

Android开发所有视频教程汇总

1.Mars的Android开发视频教程作者讲解的很详细,很全面,系统.以前出了两套视频,分别是<Java4Android视频教程>.<Android视频教程>,以及最新刚新出的<Android视频教程重制版>.很负责人的老师.具体的Mars开发视频见其个人论坛:http://www.marschen.com/bbs/forum.php <Android视频教程重制版>下载地址:http://dl.vmall.com/c0qs8budkm 2.老罗Andro

Android开发之使用MediaRecorder录制视频

MediaRecorder除了可以用于录制音频,还可用于录制视频.关于MediaRecorder的详解大家可以参考<Android开发之MediaRecorder类详解>.使用MediaRecorder录制视频与录制音频的步骤基本相同.只是录制视频时不仅需要采集声音,还需要采集图像.为了让MediaRecorder录制时采集图像,应该在调用setAudioSource(int audio source)方法时再调用setVideoSource(int video source)方法来设置图像来

Android使用的开发MediaRecorder录制视频

MediaRecorder除了使用录制音频.还可用于录制视频.关于MediaRecorder的具体解释大家能够參考<Android开发之MediaRecorder类具体解释>.使用MediaRecorder录制视频与录制音频的步骤基本同样.仅仅是录制视频时不仅须要採集声音.还须要採集图像.为了让MediaRecorder录制时採集图像,应该在调用setAudioSource(int audio source)方法时再调用setVideoSource(int video source)方法来设置

Android开发之打开闪光灯录制视频

Android的SDK在线API上对录制视频的方法.步骤都写得非常清楚,但是如果没有一点思路,写起来也比较式费事.录制视频的全过程要打开闪光灯(可能是因为项目需要,或者特殊原因),则必须按照一定的顺序进行开关,毕竟容易出错.要实现录制的同时开启闪光灯也不难,官方API给出了一个大体的步骤.因为要采集点视频数据,临时写了个简单的Demo学习下,必要时再深度开发. 首先在工程中的AndroidManifest.xml中添加权限声明,因为要使用到摄像头,故需要添加Camera的相关权限,另外还需要写S

Android开发之视频录制1

Android开发之视频录制 (2011-10-18 17:47:46) 转载▼ 标签: android 视频录制 surfaceview 杂谈 分类: 3GAndroid学习笔记 要使用视频录制功能,要用到MediaRecorder这个类,以及SurfaceView组建 public class MainActivity extends Activity { public static final String TAG = "MainActivity"; @Override prot

Android多媒体-MediaRecorder 录制音视频

不多说,直接上代码,有详细注释 MyAudioRecord.java import java.io.File; import java.io.IOException; import android.app.Activity; import android.content.ContentValues; import android.content.Intent; import android.media.MediaPlayer; import android.media.MediaRecorder

Android开发之使用MediaRecorder录制声音

为了在 Android 应用中录制声音,Android提供了 MediaRecorder 类,关于MediaRecorder的详解大家可以参考<Android开发之MediaRecorder类详解>. 使用MediaRecorder录制声音的步骤: 1) 创建 MediaRecorder 对象. 2) 调用MediaRecorder对象的setAudioSource()方法设置声音来源,一般传入 MediaRecorder. AudioSource.MIC参数指定录制来自麦克风的声音. 3)