JetPack 개발 에 서 는 CameraX 를 사용 하여 사진 촬영 과 동 영상 촬영 기능 을 완성 합 니 다.

얼마 전에 CameraX 베타 버 전이 나 왔 는데 요 며칠 동안 시도 해 보 세 요.베타 버 전 은 대외 테스트 버 전 으로 실험실 을 벗 어 나 생산 을 향 해 나 아 갔다 는 것 을 의미 하 며 API 의 호출 이 기본적으로 안정 적 이 고 크게 바 뀌 지 않 으 며 bug 도 환경 을 만 드 는 데 사용 되 지 않 을 것 이다.
카메라 1 과 카메라 2 를 사용 해 카메라 기능 을 개발 할 때 는 매우 복잡 한 API 를 사용 해 야 했 고,안 드 로 이 드 폰 의 파편 화가 심해 카메라 기능 에 대한 지원 도가 달라 카메라 관련 애플 리 케 이 션 을 하 는 회사 들 이 카메라 사용 절 차 를 간소화 하고 호환성 문 제 를 처리 하 는 경우 가 많 았 다.
CameraX 는 사실 Google 이 개발 한 카메라 개발 시 API 호출 을 간소화 하고 다양한 호환성 문 제 를 처리 하 는 라 이브 러 리 입 니 다.최대 안 드 로 이 드 5.0 까지 호 환 되 며,바 텀 호출 도 Camera 2 이지 만,Camera 2 보다 더 간단 하 며,라 이 프 사이클 을 연결 해 카메라 의 켜 기 방출 등 을 자동 으로 처리 할 수 있다.
다음 부터 해 보도 록 하 겠 습 니 다.
의존 도 를 높이다

dependencies {
 // CameraX       camera2   
 implementation "androidx.camera:camera-camera2:1.0.0-beta03"
 //     CameraView
 implementation "androidx.camera:camera-view:1.0.0-alpha10"
 //          
 implementation "androidx.camera:camera-extensions:1.0.0-alpha10"
 //camerax      
 implementation "androidx.camera:camera-lifecycle:1.0.0-beta03"
 }
CameraX 로 사진 을 찍 으 려 면 사용 상 태 를 다 르 게 설정 한 뒤 라 이 프 사이클 에 연결 하면 된다.예 를 들 어 미리 보 기 는 미리 보기 와 관련 된 상 태 를 설정 해 야 하고 사진 을 찍 으 려 면 사진 촬영 과 관련 된 상 태 를 설정 해 야 하 며 영상 을 녹화 하려 면 녹화 와 관련 된 상 태 를 설정 해 야 한다.
설정 상태
미리 보기 설정:Preview 는 카메라 미리 보기 에 미리 보기 화면 을 표시 합 니 다.

Preview preview = new Preview.Builder()
  //     
  .setTargetAspectRatio(screenAspectRatio)
  //         
  .setTargetRotation(rotation)
  .build();
사진 설정:ImageCapture 는 사진 을 찍 고 그림 을 저장 합 니 다.

ImageCapture imageCapture = new ImageCapture.Builder()
  //      ,        
  .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
  //     
  .setTargetAspectRatio(screenAspectRatio)
  //         
  .setTargetRotation(rotation)
  .build();
녹화 영상 설정:VideoCapture 는 영상 을 녹화 하고 저장 하 는 데 사용 되 며 너비 와 해상 도 를 하나 설정 하면 됩 니 다.동시에 설정 하지 마 십시오.그렇지 않 으 면 오 류 를 보고 합 니 다.실제 수요 에 따라 설정 하고 너비 와 높이 에 대한 요구 가 높 으 면 너비 와 높이 비 를 설정 하 며 반대로 해상 도 를 설정 합 니 다.

VideoCapture videoCapture = new VideoCaptureConfig.Builder()
  //      
  .setTargetRotation(rotation)
  //     
  .setTargetAspectRatio(screenAspectRatio)
  //   
  //.setTargetResolution(resolution)
  //             
  .setVideoFrameRate(25)
  //bit          
  .setBitRate(3 * 1024 * 1024)
  .build();
라 이 프 사이클 에 연결:ProcessCamera Provider 는 하나의 예 로 카메라 의 라 이 프 사이클 을 모든 LifecycleOwner 클래스 에 연결 할 수 있 습 니 다.AppCompat Activity 와 Fragment 는 모두 Lifecycle Owner 입 니 다.

//Future         ,ListenableFuture        ,            
 ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
  ProcessCameraProvider.getInstance(this);
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

//             
cameraProvider.unbindAll();

Camera camera = cameraProvider.bindToLifecycle(CameraActivity.this,
  cameraSelector,preview,imageCapture,videoCapture);
OK 미리 보기,사진 찍 기,동 영상 녹화 설정 및 라 이 프 사이클 연결 작업 완료
미리 볼 때 View 컨트롤 에 표시 해 야 합 니 다.Camera X 에 서 는 미리 보기 화면 을 표시 하 는 데 사용 되 는 PreviewView 를 제공 합 니 다.그 내 부 는 TextureView 와 SurfaceView 를 봉 하여 서로 다른 패턴 에 따라 내 부 를 TextureView 로 표시 할 지 SurfaceView 로 표시 할 지 선택 할 수 있 습 니 다.
xml 에 PreviewView 를 추가 하고 코드 에 앞에서 만 든 Preview 인 스 턴 스 에 추가 합 니 다.

<androidx.camera.view.PreviewView
 android:id="@+id/view_finder"
 android:layout_width="match_parent"
 android:layout_height="match_parent" />

 preview.setSurfaceProvider(mPreviewView.createSurfaceProvider(camera .getCameraInfo()));
이렇게 하면 우리 가 이 페이지 에 들 어 갈 때 카메라 의 미리보기 효 과 를 볼 수 있 습 니 다.다음은 사진 찍 기와 녹화 기능 을 수행 하 는 것 입 니 다.
포 토 비디오 를 실행 하 다.
사진 찍 기:

//           
 File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath(),
  System.currentTimeMillis() + ".jpeg");
 ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
 mImageCapture.takePicture(outputFileOptions,mExecutorService , new ImageCapture.OnImageSavedCallback() {
 @Override
 public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
  Uri savedUri = outputFileResults.getSavedUri();
  if(savedUri == null){
  savedUri = Uri.fromFile(file);
  }
  outputFilePath = file.getAbsolutePath();
  onFileSaved(savedUri);
 }

 @Override
 public void onError(@NonNull ImageCaptureException exception) {
  Log.e(TAG, "Photo capture failed: "+exception.getMessage(), exception);
 }
 });
//              
private void onFileSaved(Uri savedUri) {
 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
  sendBroadcast(new Intent(android.hardware.Camera.ACTION_NEW_PICTURE, savedUri));
 }
 String mimeTypeFromExtension = MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap
  .getFileExtensionFromUrl(savedUri.getPath()));
 MediaScannerConnection.scanFile(getApplicationContext(),
  new String[]{new File(savedUri.getPath()).getAbsolutePath()},
  new String[]{mimeTypeFromExtension}, new MediaScannerConnection.OnScanCompletedListener() {
   @Override
   public void onScanCompleted(String path, Uri uri) {
   Log.d(TAG, "Image capture scanned into media store: $uri"+uri);
   }
  });
 PreviewActivity.start(this, outputFilePath, !takingPicture);
 }
  • ImageCapture 의 takePicture 방법 으로 사진 을 찍 습 니 다
  • 찍 은 사진 을 저장 하기 위해 파일 주 소 를 입력 합 니 다
  • onImageSaved 방법 은 사진 을 다 찍 고 병존 한 후의 리 셋
  • 입 니 다.
  • onFileSaved 방법 은 앞 에 저 장 된 파일 을 미디어 에 추가 하고 마지막 으로 미리 보기 인터페이스 로 이동 합 니 다.
  • 비디오 녹화:
    
    //           
    File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath(),
     System.currentTimeMillis() + ".mp4");
    mVideoCapture.startRecording(file, Executors.newSingleThreadExecutor(), new VideoCapture.OnVideoSavedCallback() {
     @Override
     public void onVideoSaved(@NonNull File file) {
     outputFilePath = file.getAbsolutePath();
     onFileSaved(Uri.fromFile(file));
     }
    
     @Override
     public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
     Log.i(TAG,message);
     }
    });
    
    videoCapture.stopRecording();
  • VideoCapture 의 startRecording 방법 으로 영상 을 녹화 합 니 다
  • 비디오 를 저장 하기 위해 File 파일 을 전송 합 니 다.
  • 녹화 가 끝 난 후 onVideoSaved 방법 을 되 돌려 주 고 이 파일 의 인 스 턴 스 를 되 돌려 줍 니 다.
  • 은 onFileSaved 방법 으로 앞 에 저 장 된 파일 을 미디어 에 추가 하고 마지막 으로 미리 보기 인터페이스 로 이동 합 니 다.
  • 녹화 시간 에 도 착 했 을 때 videoCapture.stopRecording()을 호출 해 야 합 니 다.방법 은 비디오 를 멈 추 는 것 이다.
  • 여기까지 카메라 X 를 이용 해 사진 을 찍 고 동 영상 을 녹화 하 는 기능 을 모두 할 수 있 게 됐 으 니 매우 간단 하지 않 을 까.다음은 문 제 를 제외 하고 하나의 View 를 사용자 정의 하여 클릭 하여 사진 을 찍 고 비디오 를 길 게 누 르 는 효 과 를 실현 합 니 다.효 과 는 다음 과 같 습 니 다:

    코드:
    
    public class RecordView extends View implements View.OnLongClickListener, View.OnClickListener {
     private static final int PROGRESS_INTERVAL = 100;
     private int mBgColor;
     private int mStrokeColor;
     private int mStrokeWidth;
     private int mDuration;
     private int mWidth;
     private int mHeight;
     private int mRadius;
     private int mProgressValue;
     private boolean isRecording;
     private RectF mArcRectF;
     private Paint mBgPaint, mProgressPaint;
     private OnRecordListener mOnRecordListener;
     private long mStartRecordTime;
    
     public void setOnRecordListener(OnRecordListener onRecordListener) {
     mOnRecordListener = onRecordListener;
     }
    
     public RecordView(Context context) {
     this(context, null);
     }
    
     public RecordView(Context context, @Nullable AttributeSet attrs) {
     this(context, attrs, 0);
     }
    
     public RecordView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
     super(context, attrs, defStyleAttr);
     TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecordView);
     mBgColor = typedArray.getColor(R.styleable.RecordView_bg_color, Color.WHITE);
     mStrokeColor = typedArray.getColor(R.styleable.RecordView_stroke_color, Color.RED);
     mStrokeWidth = typedArray.getDimensionPixelOffset(R.styleable.RecordView_stroke_width, SizeUtils.dp2px(5));
     mDuration = typedArray.getInteger(R.styleable.RecordView_duration, 10);
     mRadius = typedArray.getDimensionPixelOffset(R.styleable.RecordView_radius, SizeUtils.dp2px(40));
     typedArray.recycle();
    
     mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     mBgPaint.setStyle(Paint.Style.FILL);
     mBgPaint.setColor(mBgColor);
    
     mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     mProgressPaint.setStyle(Paint.Style.STROKE);
     mProgressPaint.setColor(mStrokeColor);
     mProgressPaint.setStrokeWidth(mStrokeWidth);
    
     setEvent();
     }
    
     private void setEvent() {
     Handler handler = new Handler(Looper.getMainLooper()) {
      @Override
      public void handleMessage(@NonNull Message msg) {
      super.handleMessage(msg);
      mProgressValue++;
      postInvalidate();
      if (mProgressValue < mDuration*10) {
       sendEmptyMessageDelayed(0, PROGRESS_INTERVAL);
      } else {
       finishRecord();
      }
      }
     };
     setOnTouchListener(new OnTouchListener() {
      @Override
      public boolean onTouch(View v, MotionEvent event) {
      if(event.getAction() == MotionEvent.ACTION_DOWN){
       mStartRecordTime = System.currentTimeMillis();
       handler.sendEmptyMessage(0);
      }else if(event.getAction() == MotionEvent.ACTION_UP){
       long duration = System.currentTimeMillis() - mStartRecordTime;
       //               
       if(duration > ViewConfiguration.getLongPressTimeout()){
       finishRecord();
       }
       handler.removeCallbacksAndMessages(null);
       isRecording = false;
       mStartRecordTime = 0;
       mProgressValue = 0;
       postInvalidate();
      }
      return false;
      }
     });
     setOnClickListener(this);
     setOnLongClickListener(this);
     }
    
     private void finishRecord() {
      if(mOnRecordListener!=null){
      mOnRecordListener.onFinish();
      }
     }
    
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
     super.onSizeChanged(w, h, oldw, oldh);
     mWidth = w;
     mHeight = w;
     mArcRectF = new RectF(mStrokeWidth / 2f, mStrokeWidth / 2f,
      mWidth - mStrokeWidth / 2f, mHeight - mStrokeWidth / 2f);
     }
    
     @Override
     protected void onDraw(Canvas canvas) {
     super.onDraw(canvas);
    
     canvas.drawCircle(mWidth / 2f, mHeight / 2f, mRadius, mBgPaint);
    
     if (isRecording) {
      canvas.drawCircle(mWidth / 2f, mHeight / 2f, mRadius/10f*11, mBgPaint);
      float sweepAngle = 360f * mProgressValue / (mDuration*10);
      Log.i("sweepAngle",sweepAngle+"");
      canvas.drawArc(mArcRectF, -90, sweepAngle, false, mProgressPaint);
     }
    
     }
    
     @Override
     public boolean onLongClick(View v) {
     isRecording = true;
     if(mOnRecordListener!=null){
      mOnRecordListener.onRecordVideo();
     }
     return true;
     }
    
     @Override
     public void onClick(View v) {
     if(mOnRecordListener!=null){
      mOnRecordListener.onTackPicture();
     }
     }
    
     public interface OnRecordListener {
     void onTackPicture();
    
     void onRecordVideo();
    
     void onFinish();
     }
    }
    실현 도 매우 간단 합 니 다.먼저 원 을 그립 니 다.이 View 의 클릭 과 길 게 누 를 때 총 녹화 시간 과 현재 녹화 시간 에 따라 그 려 야 할 각 도 를 계산 하면 원 위 에서 진 도 를 그 릴 수 있 습 니 다.
    마지막 으로 인 터 페 이 스 를 통 해 길 게 누 르 고 녹화 가 완 료 된 사건 을 되 돌려 앞의 사진,녹화,녹화 가 완 료 된 코드 와 결합 하면 위의 효 과 를 완성 할 수 있다.
    CameraView
    앞의 초기 화가 간단 하지 않다 고 생각하면 CameraX 가 제공 하 는 CameraView 를 사용 할 수 있 습 니 다.이 안 에는 PreviewView,Preview,ImageCapture,VideoCapture 등 을 모두 봉 인 했 고 크기 조정,재단,회전 등 기능 도 실현 하여 사용 하기 가 더욱 간단 합 니 다.
    우선 xml 파일 에 CameraView 추가
    
    <androidx.camera.view.CameraView
     android:id="@+id/view_finder"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     />
    그리고 Activity 에서 CameraView 를 실례 화하 여 현재 수명 주 기 를 직접 연결 하면 됩 니 다.
    
    mBtnCameraSwitch = findViewById(R.id.camera_switch_button);
     mCameraView.bindToLifecycle(this);
    두 마디 만 하면 앞의 초기 작업 을 완성 할 수 있다.그리고 즐겁게 사진 을 찍 고 동 영상 을 녹화 할 수 있 습 니 다.
    사진 과 녹 화 된 코드 는 앞 과 마찬가지 로 모두 CamerView 대상 을 통 해 mCameraView.takePicture,mCameraView.startRecording 을 호출 할 뿐 호출 하기 전에 mCameraView.setCaptureMode(CameraView.CaptureMode.IMAGE) 을 통 해 현재 모드 가 사진 인지 비디오 인지 전환 해 야 합 니 다.
    앞 에 있 는 사용자 정의 RecordView 를 레이아웃 파일 에 넣 고 CameraView 의 사진,비디오 코드 와 결합 하면 앞 과 같은 효 과 를 곧 실현 할 수 있 습 니 다.
    사진 분석
    CameraX 는 이미지 처리,컴퓨터 시각 또는 기계 학습 으로 추정 되 는 이미 지 를 CPU 로 접근 할 수 있 는 이미지 분석 기능 도 제공 합 니 다.빈 틈 없 이 버퍼 에 접근 할 수 있 으 며 일반적으로 사용 되 지 않 지만 기능 이 강 합 니 다.그림 분석 기 를 만 들 고 성명 주 기 를 연결 하면 됩 니 다.
    
    mImageAnalysis = new ImageAnalysis.Builder()
      .setTargetAspectRatio(screenAspectRatio)
      .setTargetRotation(rotation)
      .build();
     mImageAnalysis.setAnalyzer(mExecutorService, new ImageAnalysis.Analyzer() {
      @Override
      public void analyze(@NonNull ImageProxy image) {
      
      }
     });
    cameraProvider.bindToLifecycle(CameraActivity.this,
      cameraSelector,mPreview,mImageCapture,mVideoCapture,mImageAnalysis);
    공급 자 확장
    공급 업 체 확장 프로그램:CameraX 는 외부 확장 API 를 제공 하여 핸드폰 생산 업 체 와 직접 연결 할 수 있 습 니 다.만약 에 이 핸드폰 업 체 가 CameraX 확장 프로그램 을 실현 하면 VamerX 의 확장 API 를 사용 하여 이러한 효 과 를 직접 호출 할 수 있 습 니 다.예 를 들 어 미 안,DHR,야간,자동 등 모델 입 니 다.
    모든 휴대 전화 업 체 가 확장 프로그램 을 지원 하 는 것 은 아니 기 때문에 확장 프로그램 을 사용 할 때 이 휴대 전화 가 지원 하 는 지 판단 하고 추가 해 야 합 니 다.
    미리 보기 인터페이스 에 외부 확장 을 설정 하려 면 Preview.BuilderCameraSelector cameraSelector) 두 개의 인자 가 필요 합 니 다.
    
    private void setPreviewExtender(Preview.Builder builder, CameraSelector cameraSelector) {
     AutoPreviewExtender extender = AutoPreviewExtender.create(builder);
     if(extender.isExtensionAvailable(cameraSelector)){
      extender.enableExtension(cameraSelector);
     }
     BokehPreviewExtender bokehPreviewExtender = BokehPreviewExtender.create(builder);
     if(bokehPreviewExtender.isExtensionAvailable(cameraSelector)){
      bokehPreviewExtender.enableExtension(cameraSelector);
     }
     HdrPreviewExtender hdrPreviewExtender = HdrPreviewExtender.create(builder);
     if(hdrPreviewExtender.isExtensionAvailable(cameraSelector)){
      hdrPreviewExtender.enableExtension(cameraSelector);
     }
     BeautyPreviewExtender beautyPreviewExtender = BeautyPreviewExtender.create(builder);
     if(beautyPreviewExtender.isExtensionAvailable(cameraSelector)){
      beautyPreviewExtender.enableExtension(cameraSelector);
     }
     NightPreviewExtender nightPreviewExtender = NightPreviewExtender.create(builder);
     if(nightPreviewExtender.isExtensionAvailable(cameraSelector)){
      nightPreviewExtender.enableExtension(cameraSelector);
     }
     }
    촬영 한 사진 에 외부 확장 을 설정 하려 면 ImageCapture.BuilderCameraSelector cameraSelector) 두 개의 매개 변수 가 필요 합 니 다.
    
    private void setImageCaptureExtender(ImageCapture.Builder builder, CameraSelector cameraSelector) {
     AutoImageCaptureExtender autoImageCaptureExtender = AutoImageCaptureExtender.create(builder);
     if (autoImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
      autoImageCaptureExtender.enableExtension(cameraSelector);
     }
     BokehImageCaptureExtender bokehImageCaptureExtender = BokehImageCaptureExtender.create(builder);
     if(bokehImageCaptureExtender.isExtensionAvailable(cameraSelector)){
      bokehImageCaptureExtender.enableExtension(cameraSelector);
     }
     HdrImageCaptureExtender hdrImageCaptureExtender = HdrImageCaptureExtender.create(builder);
     if(hdrImageCaptureExtender.isExtensionAvailable(cameraSelector)){
      hdrImageCaptureExtender.enableExtension(cameraSelector);
     }
     BeautyImageCaptureExtender beautyImageCaptureExtender = BeautyImageCaptureExtender.create(builder);
     if(beautyImageCaptureExtender.isExtensionAvailable(cameraSelector)){
      beautyImageCaptureExtender.enableExtension(cameraSelector);
     }
     NightImageCaptureExtender nightImageCaptureExtender = NightImageCaptureExtender.create(builder);
     if(nightImageCaptureExtender.isExtensionAvailable(cameraSelector)){
      nightImageCaptureExtender.enableExtension(cameraSelector);
     }
     }
    demo 주소:주소 링크
    총결산
    여기에 JetPack 의 CameraX 사용 완성 사진 과 동 영상 촬영 에 관 한 글 이 소개 되 었 습 니 다.더 많은 JetPack 은 CameraX 를 사용 하여 사진 을 찍 고 동 영상 을 찍 는 내용 에 대해 서 는 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

    좋은 웹페이지 즐겨찾기