Camera1

https://blog.csdn.net/qq_38907791/article/details/87984378
源码
https://www.cnblogs.com/zhujiabin/p/4218209.htmls
//布局
<RelativeLayout
        android:id="@+id/layout_gesture"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#000"
        android:gravity="center_horizontal">
    <SurfaceView
        android:id="@+id/record_surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    </RelativeLayout>

    <ImageView
        android:id="@+id/changing"
        android:background="@drawable/rotate"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:layout_width="30dp"
        android:layout_height="30dp" />

    <ImageView
        android:id="@+id/change"
        android:background="@drawable/rotate"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp"
        android:layout_width="30dp"
        android:layout_height="30dp" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="#80ffffff"
        android:padding="10dp">

        <!-- 开始/结束 录制按钮 -->
        <ImageView
            android:id="@+id/record_control"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_centerInParent="true"
            android:onClick="startRecord"
            android:src="@drawable/recordvideo_start" />

        <ImageView
            android:id="@+id/record_pause"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_centerVertical="true"
            android:onClick="stopRecord"
            android:src="@drawable/control_pause"
            android:visibility="gone" />

        <Chronometer
            android:id="@+id/record_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:format="%s" />
    </RelativeLayout>

import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import camera1video.android.example.com.android_camera1video_master.util.VideoUtils;

public class CustomRecordActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "CustomRecordActivity";

    private Executor executor = Executors.newFixedThreadPool(1);

    private ImageView mRecordControl;
    private ImageView mPauseRecord;
    private ImageView mChange;
    private ImageView mChanging;
    private SurfaceView surfaceView;
    private SurfaceHolder mSurfaceHolder;
    private Chronometer mRecordTime;

    //录像机状态标识
    private int mRecorderState;
    public static final int STATE_INIT = 0;
    public static final int STATE_RECORDING = 1;
    public static final int STATE_PAUSE = 2;
    public static final int CAMERA_OK = 1;
    private long mPauseTime = 0; //录制暂停时间间隔
    int cameraType = 0;
    int cameraFlag = 1; //1为后置
    int flashType;

    // 存储文件
    private Camera mCamera;
    private MediaRecorder mediaRecorder;
    private String currentVideoFilePath;
    private String saveVideoPath = "";
    private String str = null;

    private MediaRecorder.OnErrorListener OnErrorListener = new MediaRecorder.OnErrorListener() {
        @Override
        public void onError(MediaRecorder mediaRecorder, int what, int extra) {
            try {
                if (mediaRecorder != null) {
                    mediaRecorder.reset();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        if (Build.VERSION.SDK_INT > 22) {
            if (ContextCompat.checkSelfPermission(CustomRecordActivity.this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                //先判断有没有权限 ,没有就在这里进行权限的申请
                ActivityCompat.requestPermissions(CustomRecordActivity.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO}, CAMERA_OK);
                initView();
            } else {
                //说明已经获取到摄像头权限了
                Log.i("CustomRecordActivity", "已经获取了权限");
                initView();
            }
        }
    }

    private void initView() {
        surfaceView = (SurfaceView) findViewById(R.id.record_surfaceView);
        mRecordControl = (ImageView) findViewById(R.id.record_control);
        mRecordTime = (Chronometer) findViewById(R.id.record_time);
        mPauseRecord = (ImageView) findViewById(R.id.record_pause);
        mChange = (ImageView) findViewById(R.id.change);
        mChanging = (ImageView) findViewById(R.id.changing);
        mRecordControl.setOnClickListener(this);
        mPauseRecord.setOnClickListener(this);
        mChange.setOnClickListener(this);
        mChanging.setOnClickListener(this);
        mPauseRecord.setEnabled(false);

        /*ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
        lp.width = 720;
        lp.height =1280;
        surfaceView.setLayoutParams(lp);*/

        //配置SurfaceHolder
        mSurfaceHolder = surfaceView.getHolder();
        // 设置Surface不需要维护自己的缓冲区
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        // 设置分辨率
        mSurfaceHolder.setFixedSize(720, 1280);
        // 设置该组件不会让屏幕自动关闭
        mSurfaceHolder.setKeepScreenOn(true);
        //回调接口
        mSurfaceHolder.addCallback(mSurfaceCallBack);
    }

    private SurfaceHolder.Callback mSurfaceCallBack = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            initCamera();
        }

        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
            if (mSurfaceHolder.getSurface() == null) {
                return;
            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            releaseCamera();
        }
    };

    /**
     * 设置摄像头为竖屏
     */
    private void configCameraParams() {
        Camera.Parameters params = mCamera.getParameters();
       /* str = params.get("video-rotation-supported");
        if (str != null ) {
            if (str.equals("true")) {
                Log.e("video-rotation-111","str支持旋转");
                Show();
            } else {
                Log.e("video-rotation-333","str不支持旋转");
                Show();
            }
        }else {
            Log.e("video-rotation-222","不支持旋转");
            NoShow();
        }*/
        params.setPreviewSize(720,1280);
        //设置相机的横竖屏(竖屏需要旋转90°)
        if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
            //params.set("orientation", "portrait");
            params.set("video-rotation","90");
            //设置预览图像的旋转方向video-rotation=90
            //mCamera.setDisplayOrientation(0);
        } else {
            //params.set("orientation", "landscape");
            params.set("video-rotation","0");
            //设置预览图像的旋转方向
            //mCamera.setDisplayOrientation(90);
        }
        //设置聚焦模式
        params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        //缩短Recording启动时间
        params.setRecordingHint(true);
        //影像稳定能力
        if (params.isVideoStabilizationSupported())
            params.setVideoStabilization(true);
        mCamera.setParameters(params);
        //mCamera.setDisplayOrientation(90);
    }

    private void Show() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this).setIcon(R.mipmap.ic_launcher).setTitle("支持旋转")
                .setCancelable(false)
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        dialogInterface.dismiss();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        dialogInterface.dismiss();
                    }
                });
        builder.create().show();
    }

    private void NoShow() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this).setIcon(R.mipmap.ic_launcher).setTitle("不支持旋转")
                .setCancelable(false)
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        dialogInterface.dismiss();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        dialogInterface.dismiss();
                    }
                });
        builder.create().show();
    }

    /**
     * 释放摄像头资源
     */
    private void releaseCamera() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    /**
     * 开始录制视频
     */
    public boolean startRecord() {
        initCamera();
        //录制视频前必须先解锁Camera
        mCamera.unlock();
        configMediaRecorder();
        try {
            //开始录制
            mediaRecorder.prepare();
            mediaRecorder.start();
        } catch (IOException e) {
            return false;
        }
        return true;
    }

    /**
     * 停止录制视频
     */
    public void stopRecord() {
        // 设置后不会崩
        mediaRecorder.setOnErrorListener(null);
        mediaRecorder.setPreviewDisplay(null);
        //停止录制
        mediaRecorder.stop();
        mediaRecorder.reset();
        //释放资源
        mediaRecorder.release();
        mediaRecorder = null;
    }

    /**
     * 合并录像视频方法
     */
    private void mergeRecordVideoFile() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String[] str = new String[]{saveVideoPath, currentVideoFilePath};
                    //将2个视频文件合并到 append.mp4文件下
                    VideoUtils.appendVideo(CustomRecordActivity.this, getVideoFilePath(CustomRecordActivity.this) + "append.mp4", str);
                    File reName = new File(saveVideoPath);
                    File f = new File(getVideoFilePath(CustomRecordActivity.this) + "append.mp4");
                    //再将合成的append.mp4视频文件 移动到 saveVideoPath 路径下
                    f.renameTo(reName);
                    if (reName.exists()) {
                        f.delete();
                        new File(currentVideoFilePath).delete();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 点击中间按钮,执行的UI更新操作
     */
    private void refreshControlUI() {
        if (mRecorderState == STATE_INIT) {
            //录像时间计时
            mRecordTime.setBase(SystemClock.elapsedRealtime());
            mRecordTime.start();
            mRecordControl.setImageResource(R.drawable.recordvideo_stop);
            //1s后才能按停止录制按钮
            mRecordControl.setEnabled(false);
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mRecordControl.setEnabled(true);
                }
            }, 1000);
            mPauseRecord.setVisibility(View.VISIBLE);
            mPauseRecord.setEnabled(true);
        } else if (mRecorderState == STATE_RECORDING) {
            mPauseTime = 0;
            mRecordTime.stop();
            mRecordControl.setImageResource(R.drawable.recordvideo_start);
            mPauseRecord.setVisibility(View.GONE);
            mPauseRecord.setEnabled(false);
        }
    }

    /**
     * 点击暂停继续按钮,执行的UI更新操作
     */
    private void refreshPauseUI() {
        if (mRecorderState == STATE_RECORDING) {
            mPauseRecord.setImageResource(R.drawable.control_play);
            mPauseTime = SystemClock.elapsedRealtime();
            mRecordTime.stop();
        } else if (mRecorderState == STATE_PAUSE) {
            mPauseRecord.setImageResource(R.drawable.control_pause);
            if (mPauseTime == 0) {
                mRecordTime.setBase(SystemClock.elapsedRealtime());
            } else {
                mRecordTime.setBase(SystemClock.elapsedRealtime() - (mPauseTime - mRecordTime.getBase()));
            }
            mRecordTime.start();
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.record_control: {
                if (mRecorderState == STATE_INIT) {
                    if (getVideoFilePath(getApplicationContext()) == null)
                        return;
                    //视频文件保存路径,configMediaRecorder方法中会设置
                    currentVideoFilePath = getVideoFilePath(getApplicationContext()) + getVideoName();
                    //开始录制视频
                    if (!startRecord())
                        return;
                    refreshControlUI();
                    mRecorderState = STATE_RECORDING;
                } else if (mRecorderState == STATE_RECORDING) {
                    //停止视频录制
                    stopRecord();
                    //先给Camera加锁后再释放相机
                    mCamera.lock();
                    releaseCamera();
                    refreshControlUI();
                    //判断是否进行视频合并
                    if ("".equals(saveVideoPath)) {
                        saveVideoPath = currentVideoFilePath;
                    } else {
                        mergeRecordVideoFile();
                    }
                    mRecorderState = STATE_INIT;
                    //延迟一秒跳转到播放器,(确保视频合并完成后跳转) TODO 具体的逻辑可根据自己的使用场景跳转
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            Intent intent = new Intent(CustomRecordActivity.this, PlayVideoActivity.class);
                            Bundle bundle = new Bundle();
                            bundle.putString("videoPath", saveVideoPath);
                            intent.putExtras(bundle);
                            startActivity(intent);
                            finish();
                        }
                    }, 1000);
                } else if (mRecorderState == STATE_PAUSE) {
                    //代表视频暂停录制时,点击中心按钮
                    Intent intent = new Intent(CustomRecordActivity.this, PlayVideoActivity.class);
                    Bundle bundle = new Bundle();
                    bundle.putString("videoPath", saveVideoPath);
                    intent.putExtras(bundle);
                    startActivity(intent);
                    finish();
                }
                break;
            }

            case R.id.record_pause: {
                if (mRecorderState == STATE_RECORDING) {
                    //正在录制的视频,点击后暂停
                    //取消自动对焦
                    mCamera.autoFocus(new Camera.AutoFocusCallback() {
                        @Override
                        public void onAutoFocus(boolean success, Camera camera) {
                            if (success)
                                CustomRecordActivity.this.mCamera.cancelAutoFocus();
                        }
                    });
                    stopRecord();
                    refreshPauseUI();
                    //判断是否进行视频合并
                    if ("".equals(saveVideoPath)) {
                        saveVideoPath = currentVideoFilePath;
                    } else {
                        mergeRecordVideoFile();
                    }
                    mRecorderState = STATE_PAUSE;
                } else if (mRecorderState == STATE_PAUSE) {
                    if (getVideoFilePath(getApplicationContext()) == null)
                        return;
                    //视频文件保存路径,configMediaRecorder方法中会设置
                    currentVideoFilePath = getVideoFilePath(getApplicationContext()) + getVideoName();
                    //继续视频录制
                    if (!startRecord()) {
                        return;
                    }
                    refreshPauseUI();
                    mRecorderState = STATE_RECORDING;
                }
            }

            case R.id.change:
                switchCamera();
                break;

            case R.id.changing:
                // 一个自定义的布局,作为显示的内容
                View contentView = LayoutInflater.from(this).inflate(
                        R.layout.popu, null);
                final PopupWindow popupWindow = new PopupWindow(contentView,
                        ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);

                contentView.findViewById(R.id.num1).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        popupWindow.dismiss();
                        View content = LayoutInflater.from(CustomRecordActivity.this).inflate(
                                R.layout.popuwindow, null);
                        final PopupWindow popup = new PopupWindow(content,
                                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);

                        content.findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                popup.dismiss();
                                ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
                                lp.width = 120;
                                lp.height =160;
                                surfaceView.setLayoutParams(lp);
                            }
                        });

                        content.findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                popup.dismiss();
                                ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
                                lp.width = 420;
                                lp.height =640;
                                surfaceView.setLayoutParams(lp);
                            }
                        });

                        content.findViewById(R.id.btn3).setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                popup.dismiss();
                                ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
                                lp.width = 720;
                                lp.height =1280;
                                surfaceView.setLayoutParams(lp);
                            }
                        });

                        content.findViewById(R.id.btn4).setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                popup.dismiss();
                                ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
                                lp.width = 1280;
                                lp.height =1920;
                                surfaceView.setLayoutParams(lp);
                            }
                        });

                        popup.setTouchable(true);

                        popup.setTouchInterceptor(new View.OnTouchListener() {

                            @Override
                            public boolean onTouch(View v, MotionEvent event) {

                                Log.i("mengdd", "onTouch : ");

                                return false;
                                // 这里如果返回true的话,touch事件将被拦截
                                // 拦截后 PopupWindow的onTouchEvent不被调用,这样点击外部区域无法dismiss
                            }
                        });

                        // 如果不设置PopupWindow的背景,无论是点击外部区域还是Back键都无法dismiss弹框
                        // 我觉得这里是API的一个bug
                        popup.setBackgroundDrawable(getResources().getDrawable(
                                R.drawable.ic_launcher_background));

                        // 设置好参数之后再show
                        popup.showAsDropDown(view);
                    }
                });

                contentView.findViewById(R.id.num2).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        Toast.makeText(CustomRecordActivity.this,"旋转",Toast.LENGTH_SHORT);
                        Camera.Parameters params = mCamera.getParameters();
                        str = params.get("video-rotation-supported");
                        if (str != null ) {
                            if (str.equals("true")) {
                                Log.e("video-rotation-111","str支持旋转");
                                Show();
                                popupWindow.dismiss();
                            } else {
                                Log.e("video-rotation-333","str不支持旋转");
                                NoShow();
                                popupWindow.dismiss();
                            }
                        }else {
                            Log.e("video-rotation-222","不支持旋转");
                            NoShow();
                            popupWindow.dismiss();
                        }
                        params.setPreviewSize(720,1280);
                        //设置相机的横竖屏(竖屏需要旋转90°)
                        if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
                            //params.set("orientation", "portrait");
                            params.set("video-rotation","90");
                            //设置预览图像的旋转方向video-rotation=90
                            //mCamera.setDisplayOrientation(0);
                        } else {
                            //params.set("orientation", "landscape");
                            params.set("video-rotation","0");
                            //设置预览图像的旋转方向
                            //mCamera.setDisplayOrientation(90);
                        }
                        //设置聚焦模式
                        params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
                        //缩短Recording启动时间
                        params.setRecordingHint(true);
                        //影像稳定能力
                        if (params.isVideoStabilizationSupported())
                            params.setVideoStabilization(true);
                        mCamera.setParameters(params);
                        //mCamera.setDisplayOrientation(90);
                    }
                });

                popupWindow.setTouchable(true);

                popupWindow.setTouchInterceptor(new View.OnTouchListener() {

                    @Override
                    public boolean onTouch(View v, MotionEvent event) {

                        Log.i("mengdd", "onTouch : ");

                        return false;
                        // 这里如果返回true的话,touch事件将被拦截
                        // 拦截后 PopupWindow的onTouchEvent不被调用,这样点击外部区域无法dismiss
                    }
                });

                // 如果不设置PopupWindow的背景,无论是点击外部区域还是Back键都无法dismiss弹框
                // 我觉得这里是API的一个bug
                popupWindow.setBackgroundDrawable(getResources().getDrawable(
                        R.drawable.ic_launcher_background));

                // 设置好参数之后再show
                popupWindow.showAsDropDown(view);
                break;
        }

    }

    /**
     * 初始化摄像头
     *
     * @throws IOException
     */
    private void initCamera() {
        if (mCamera != null) {
            releaseCamera();
        }
            mCamera = Camera.open(0);
        if (mCamera == null) {
            Toast.makeText(this, "未能获取到相机!", Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            //将相机与SurfaceHolder绑定
            mCamera.setPreviewDisplay(mSurfaceHolder);
            //配置CameraParams
            configCameraParams();
            //启动相机预览
            mCamera.startPreview();
        } catch (IOException e) {
            //有的手机会因为兼容问题报错,这就需要开发者针对特定机型去做适配了
            Log.e(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }

    /**
     * 切换摄像头
     */
    public void switchCamera() {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        int cameraCount = Camera.getNumberOfCameras();//得到摄像头的个数0或者1;
        try {
            for (int i = 0; i < cameraCount; i++) {
                Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息
                if (cameraFlag == 1) {
                    //后置到前置
                    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {//代表摄像头的方位,CAMERA_FACING_FRONT前置      CAMERA_FACING_BACK后置
                        //frontCameraRotate();//前置旋转摄像头度数
                        switchCameraLogic(i, 0, 90);
                        break;
                    }
                } else {
                    //前置到后置
                    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {//代表摄像头的方位,CAMERA_FACING_FRONT前置      CAMERA_FACING_BACK后置
                        switchCameraLogic(i, 1, 90);
                        break;
                    }
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /***
     * 处理摄像头切换逻辑
     *
     * @param i           哪一个,前置还是后置
     * @param flag        切换后的标志
     * @param orientation 旋转的角度
     */
    private void switchCameraLogic(int i, int flag, int orientation) {
        if (mCamera != null) {
            mCamera.lock();
        }
        releaseCamera();
        mCamera = Camera.open(i);//打开当前选中的摄像头
        try {
            mCamera.setDisplayOrientation(orientation);
            mCamera.setPreviewDisplay(mSurfaceHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        cameraFlag = flag;
        FlashLogic(mCamera.getParameters(), 0, false);
        mCamera.startPreview();
        cameraType = i;
        mCamera.unlock();
    }

    /**
     * 闪光灯逻辑
     *
     * @param p    相机参数
     * @param type 打开还是关闭
     * @param isOn 是否启动
     */
    private void FlashLogic(Camera.Parameters p, int type, boolean isOn) {
        flashType = type;
        if (type == 0) {
            if (isOn) {
                p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                mCamera.setParameters(p);
            }
        } else {
            if (isOn) {
                p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                mCamera.setParameters(p);
            }
        }
    }

    /**
     * 配置MediaRecorder()
     */
    private void configMediaRecorder() {
        mediaRecorder = new MediaRecorder();
        mediaRecorder.reset();
        mediaRecorder.setCamera(mCamera);
        mediaRecorder.setOnErrorListener(OnErrorListener);
        //使用SurfaceView预览
        mediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
        //1.设置采集声音
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        //设置采集图像
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        //2.设置视频,音频的输出格式 mp4
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
        //3.设置音频的编码格式
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        //设置图像的编码格式
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        //音频一秒钟包含多少数据位
        CamcorderProfile mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
        mediaRecorder.setAudioEncodingBitRate(44100);
        if (mProfile.videoBitRate > 2 * 1024 * 1024) {
            mediaRecorder.setVideoEncodingBitRate(2 * 1024 * 1024);
            Log.e("aaa","1024*1024");
        }
        else {
            mediaRecorder.setVideoEncodingBitRate(1024 * 1024);
            Log.e("bbb","1024*1024");
        }
        mediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
        //设置选择角度,顺时针方向,因为默认是逆向90度的,这样图像就是正常显示了,这里设置的是观看保存后的视频的角度
        mediaRecorder.setOrientationHint(90);
        //设置录像的分辨率
        mediaRecorder.setVideoSize(720, 1280);
        //设置录像视频输出地址
        mediaRecorder.setOutputFile(currentVideoFilePath);
    }

    /**
     * 创建视频文件保存路径
     */
    private String getVideoFilePath(Context context) {
        final File dir = context.getExternalFilesDir(null);
        return (dir == null ? "" : (dir.getAbsolutePath() + "/"))
                + System.currentTimeMillis() + ".mp4";
    }
    public static String getSDPath(Context context) {
        if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
            Toast.makeText(context, "请查看您的SD卡是否存在!", Toast.LENGTH_SHORT).show();
            return null;
        }
        File sdDir = Environment.getExternalStorageDirectory();
        File eis = new File(sdDir.toString() + "/RecordVideo/");
        if (!eis.exists()) {
            eis.mkdir();
        }
        return sdDir.toString() + "/RecordVideo/";
    }

    private String getVideoName() {
        return "VID_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".mp4";
    }

    //activity监听屏幕旋转
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            // Nothing need to be done here
            Log.e("TAG", "横屏");
            Toast.makeText(this, "1", Toast.LENGTH_SHORT);
            //处理代码
            // 设置分辨率
            ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
            lp.width = 720;
            lp.height =1280;
            surfaceView.setLayoutParams(lp);
        } else {
            // Nothing need to be done here
            Log.e("TAG", "竖屏");
            Toast.makeText(this, "1", Toast.LENGTH_SHORT);
            //处理代码
            // 设置分辨率
            ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
            lp.width = 720;
            lp.height =1280;
            surfaceView.setLayoutParams(lp);
        }
    }
}
//权限
<uses-permission android:name="android.permission.FLASHLIGHT" />
    <!--相机必须权限-->
    <uses-permission android:name="android.permission.CAMERA" />
    <!--相机录像权限-->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!--存储读写权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!--如果需要用GPS位置信息标记图像,则必须请求设置此权限-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <!-- 下面这个特性声明针对Android 5(API级别21)或更高才需要添加-->
    <uses-feature android:name="android.hardware.location.gps" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.hardware.camera.autofocus" />
    <uses-feature android:name="android.hardware.autofocus"/>
<SurfaceView
        android:id="@+id/record_surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="#80ffffff"
        android:padding="10dp">

        <!-- 开始/结束 录制按钮 -->
        <ImageView
            android:id="@+id/record_control"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_centerInParent="true"
            android:onClick="startRecord"
            android:src="@drawable/recordvideo_start" />

        <ImageView
            android:id="@+id/record_pause"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_centerVertical="true"
            android:onClick="stopRecord"
            android:src="@drawable/control_pause"
            android:visibility="gone" />

        <Chronometer
            android:id="@+id/record_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:format="%s" />

    </RelativeLayout>
control_pause.png
control_play.png
record_camera_switch_normal.png
recordvideo_start.png
recordvideo_stop.png
seek_bkg.png
seekbar_thumb_normal.png
seekbar_thumb_pressed.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,699评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,124评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,127评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,342评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,356评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,057评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,654评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,572评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,095评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,205评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,343评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,015评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,704评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,196评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,320评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,690评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,348评论 2 358