android自定义相机取景框模仿微信抓取录像实现活体认证

android自定义相机取景框模仿微信抓取录像实现活体认证
出于费用成本的考虑,以及百度的图片识别度相对于华为准确度不那么高(驾驶证行驶证识别不太给力,反光时候,识别出差率比较高)。最近公司决定将身份认证模块由原来的调用第三方百度AI改为华为AI,由于百度android sdk的全部封装好了,只需要调用接口即可完成所有功能,而华为没有活体认证android相关sdk,需要开发者自己上传检测活体视频,为了便捷抓取头部部位,那么就需要开发者自定义相机取景框,上传录像小视频,调用华为认证接口去实现身份认证。
1、实现方式
camera2+MediaRecorder+TextureView+CircleVideoProgressBar+(上传抓取的录像文件+调取接口代码就不上了)

2、过程
1.一开始想用别人的PictureSelector(不了解的可以自行搜索)去实现,发现好像不能默认打开前置摄像头,且需求需要对取景框做调整,又不想把代码下载下来改源码(放弃)
2.直接通过intent 直接调用
/拍摄视频

int durationLimit = getVideoCaptureDurationLimit(); 
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, sizeLimit);
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, durationLimit);
startActivityForResult(intent, REQUEST_CODE_TAKE_VIDEO);

这种也不行,EXTRA_VIDEO_QUALITY值设为0清晰度过低,模糊,设为1清晰度有了,但是5秒的视频占用空间高的有40M,直接上传的话体验不太好,在手机上压缩也需要20秒+,显然不符合要求(放弃)
3.网络寻觅了一会,好多都是互相抄的,以前老一套的东西为多,用Camera这个类做的,这个类已经过时许久了,且发现它并不兼容现在的多摄像头安卓高版本手机(弃用)

3.说说思路****
(1)自定义CircleTextureView,活体抓取录像需要的圆型相机取景框;

 public class CircleTextureView extends TextureView {
    private int mRatioWidth = 0;
    private int mRatioHeight = 0;
public CircleTextureView(Context context) {
    this(context, null);
}

public CircleTextureView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public CircleTextureView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    setOutlineProvider(new ViewOutlineProvider() {
        @Override
        public void getOutline(View view, Outline outline) {
            float pxValue = WindowDispaly.dip2px(context, 150);
            Rect rect = new Rect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
            outline.setRoundRect(rect, pxValue);
        }
    });
    setClipToOutline(true);
}
/**
 * @param width  Relative horizontal size
 * @param height Relative vertical size
 */
public void setAspectRatio(int width, int height) {
    if (width < 0 || height < 0) {
        throw new IllegalArgumentException("Size cannot be negative.");
    }
    mRatioWidth = width;
    mRatioHeight = height;
    requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
    } else {
        if (width < height * mRatioWidth / mRatioHeight) {
            setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
        } else {
            setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
        }
    }
}

}

(2)写一个相机管理类CameraController:

 public class CameraController {
    private static final String TAG = "CameraController";
    private static Activity mActivity;
    private String mFolderPath; //保存视频,图片的文件夹路径
    private ImageReader mImageReader;
    private HandlerThread mBackgroundThread;
    private Handler mBackgroundHandler;
    private CircleTextureView mTextureView;
    //一个信号量以防止应用程序在   关闭相机之前退出。
    private Semaphore mCameraOpenCloseLock = new Semaphore(1);
    private String mCameraId;//当前相机的ID。
    private CameraDevice mCameraDevice;
    private Size mPreviewSize;
    private CaptureRequest.Builder mPreviewRequestBuilder;
    private CameraCaptureSession mCaptureSession;
    private CaptureRequest mPreviewRequest;
    private File mFile;//拍照储存文件
    private Integer mSensorOrientation;
    private CameraCaptureSession mPreviewSession;
    private CaptureRequest.Builder mPreviewBuilder;
    private static final int MAX_PREVIEW_WIDTH = 1920;//Camera2 API保证的最大预览宽度
    private static final int MAX_PREVIEW_HEIGHT = 1080;//Camera2 API保证的最大预览高度
    private boolean mFlashSupported;
    private int mState = STATE_PREVIEW;
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
    static {
        ORIENTATIONS.append(Surface.ROTATION_0, 90);
        ORIENTATIONS.append(Surface.ROTATION_90, 0);
        ORIENTATIONS.append(Surface.ROTATION_180, 270);
        ORIENTATIONS.append(Surface.ROTATION_270, 180);
    }
    private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
    private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
    private static final int STATE_PREVIEW = 0;//相机状态:显示相机预览。
    private static final int STATE_WAITING_LOCK = 1;//相机状态:等待焦点被锁定。
    private static final int STATE_WAITING_PRECAPTURE = 2;//等待曝光被Precapture状态。
    //相机状态:等待曝光的状态是不是Precapture。
    private static final int STATE_WAITING_NON_PRECAPTURE = 3;
    private static final int STATE_PICTURE_TAKEN = 4;//相机状态:拍照。
    private MediaRecorder mMediaRecorder;
    private String mNextVideoAbsolutePath;
    private String saveVideoTempPath;
    private CameraController() {
    }
    private static class ClassHolder {
        static CameraController mInstance = new CameraController();
    }
    public static CameraController getmInstance(Activity activity) {
        mActivity = activity;
        return ClassHolder.mInstance;
    }
    public void InitCamera(CircleTextureView textureView) {
        this.mTextureView = textureView;
        startBackgroundThread();
        if (mTextureView.isAvailable()) {
            openCamera(mTextureView.getWidth(), mTextureView.getHeight());
        } else {
            mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
        }
    }
    /**
     * 设置需要保存文件的文件夹路径
     * @param path
     */
    public void setFolderPath(String path) {
        this.mFolderPath = path;
        File mFolder = new File(path);
        if (!mFolder.exists()) {
            mFolder.mkdirs();
            Log.e(TAG, "文件夹不存在去创建");
        } else {
            Log.e(TAG, "文件夹已创建");
        }
    }
    public String getFolderPath() {
        return mFolderPath;
    }
/**
 * 拍照
 */
public void takePicture() {
    lockFocus();
}

/**
 * 开始录像
 */
public void startRecordingVideo() {

    if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
        return;
    }
    try {
        closePreviewSession();
        setUpMediaRecorder();
        SurfaceTexture texture = mTextureView.getSurfaceTexture();
        assert texture != null;
        texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
        List<Surface> surfaces = new ArrayList<>();

        //为相机预览设置曲面
        Surface previewSurface = new Surface(texture);
        surfaces.add(previewSurface);
        mPreviewBuilder.addTarget(previewSurface);

        //设置MediaRecorder的表面
        Surface recorderSurface = mMediaRecorder.getSurface();
        surfaces.add(recorderSurface);
        mPreviewBuilder.addTarget(recorderSurface);

        // 启动捕获会话
        // 一旦会话开始,我们就可以更新UI并开始录制
        mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {

            @Override
            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                mPreviewSession = cameraCaptureSession;
                updatePreview();
                mActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //开启录像
                        mMediaRecorder.start();
                    }
                });
            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {


            }
        }, mBackgroundHandler);
    } catch (CameraAccessException | IOException e) {
        e.printStackTrace();
    }
}

/**
 * 停止录像
 */
public void stopRecordingVideo() {
    saveVideoTempPath = mNextVideoAbsolutePath;
    Uri uri = Uri.fromFile(new File(mNextVideoAbsolutePath));
    Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);//通知更新图库
    intent.setData(uri);
    mActivity.sendBroadcast(intent);
    mMediaRecorder.stop();
    mMediaRecorder.reset();
    mNextVideoAbsolutePath = null;
    startPreview();
}
public String getSavePath() {
    return saveVideoTempPath;
}

private void closePreviewSession() {
    if (mPreviewSession != null) {
        mPreviewSession.close();
        mPreviewSession = null;
    }
}
private void setUpMediaRecorder() throws IOException {
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //设置用于录制的音源
    //开始捕捉和编码数据到 setOutputFile(指定的文件)
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android自定义相机取景框可以通过自定义View来实现。具体步骤如下: 1.在布局文件中添加SurfaceView和自定义View,其中SurfaceView用于相机预览,自定义View用于绘制取景框。 2.在Activity中获取SurfaceView和自定义View的实例,并在SurfaceView的回调函数中打开相机。 3.在自定义View的onDraw()方法中绘制取景框。 4.在Activity中实现相机拍照的回调函数,并在回调函数中获取拍照的图片。 5.在自定义View中添加手势监听器,实现取景框的移动和缩放功能。 代码示例: ``` //布局文件 <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> <com.example.myapp.MyView android:id="@+id/myView" android:layout_width="match_parent" android:layout_height="match_parent" /> //Activity中的代码 public class CameraActivity extends Activity implements SurfaceHolder.Callback { private SurfaceView mSurfaceView; private MyView mMyView; private Camera mCamera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView); mMyView = (MyView) findViewById(R.id.myView); SurfaceHolder holder = mSurfaceView.getHolder(); holder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { mCamera = Camera.open(); try { mCamera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } mCamera.startPreview(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mCamera.stopPreview(); Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(width, height); mCamera.setParameters(parameters); mCamera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { mCamera.stopPreview(); mCamera.release(); } private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { //获取拍照的图片 } }; } //自定义View中的代码 public class MyView extends View { private Rect mRect = new Rect(100, 100, 500, 500); private Paint mPaint = new Paint(); public MyView(Context context, AttributeSet attrs) { super(context, attrs); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); } @Override protected void onDraw(Canvas canvas) { canvas.drawRect(mRect, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { //实现取景框的移动和缩放功能 return true; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值