主頁 > 知識庫 > JetPack開發(fā)中使用CameraX完成拍照和拍視頻功能

JetPack開發(fā)中使用CameraX完成拍照和拍視頻功能

熱門標簽:地圖標注資源分享注冊 北京外呼系統(tǒng)咨詢電話 高德地圖標注公司位置需要錢嗎 合肥阿里辦理400電話號 襄陽外呼增值業(yè)務線路解決方案 廊坊地圖標注申請入口 海南人工外呼系統(tǒng)哪家好 怎么去掉地圖標注文字 慶陽外呼系統(tǒng)定制開發(fā)

前段時間CameraX的Beta版發(fā)布了,這幾天有時間也來嘗試一下。Beta版本是對外測試版本,意味著它已經(jīng)走出實驗室走向生產(chǎn),API的調(diào)用基本穩(wěn)定不會大改了,bug也會更少可以用于生成環(huán)境。

之前使用Camera1和Camera2開發(fā)相機功能的時候需要調(diào)用非常復雜的API,而且由于Android手機的碎片化嚴重,不同手機對相機功能的支持度也不一樣,因此很多做相機相關應用的公司都會封裝自己的相機庫來簡化相機的使用步驟和處理兼容性問題。

CameraX其實就是Google開發(fā)的一個用來簡化相機開發(fā)時候API的調(diào)用和處理各種兼容性問題的庫。最多兼容到Android 5.0,底層調(diào)用的也是Camera2,不過比Camera2用起來更簡單,而且可以綁定生命周期,從而可以自動的處理相機的開啟釋放等工作。

下面開始來嘗試吧

添加依賴

dependencies {
 // CameraX 核心庫使用 camera2 實現(xiàn)
 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拍照非常簡單,只需要配置不同的使用狀態(tài),然后綁定到生命周期中即可。比如預覽需要設置預覽相關的狀態(tài),拍照需要設置拍照相關的狀態(tài),錄制視頻需要設置錄制相關的狀態(tài)。

配置狀態(tài)

預覽配置:Preview用于相機預覽的時候顯示預覽畫面。

Preview preview = new Preview.Builder()
  //設置寬高比
  .setTargetAspectRatio(screenAspectRatio)
  //設置當前屏幕的旋轉(zhuǎn)
  .setTargetRotation(rotation)
  .build();

照相配置:ImageCapture 用于拍照,并將圖片保存

ImageCapture imageCapture = new ImageCapture.Builder()
  //優(yōu)化捕獲速度,可能降低圖片質(zhì)量
  .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
  //設置寬高比
  .setTargetAspectRatio(screenAspectRatio)
  //設置初始的旋轉(zhuǎn)角度
  .setTargetRotation(rotation)
  .build();

錄制視頻設置:VideoCapture 用來錄制視頻和保存視頻,寬高比和分辨率設置一個就可以了,不要同時設置否則報錯。根據(jù)實際的需求來設置,如果對寬高比要求高就設置寬高比,反之就設置分辨率

VideoCapture videoCapture = new VideoCaptureConfig.Builder()
  //設置當前旋轉(zhuǎn)
  .setTargetRotation(rotation)
  //設置寬高比
  .setTargetAspectRatio(screenAspectRatio)
  //分辨率
  //.setTargetResolution(resolution)
  //視頻幀率 越高視頻體積越大
  .setVideoFrameRate(25)
  //bit率 越大視頻體積越大
  .setBitRate(3 * 1024 * 1024)
  .build();

綁定到生命周期:ProcessCameraProvider 是一個單例類,可以把相機的生命周期綁定到任何LifecycleOwner類中。AppCompatActivity和Fragment都是LifecycleOwner

//Future表示一個異步的任務,ListenableFuture可以監(jiān)聽這個任務,當任務完成的時候執(zhí)行回調(diào)
 ListenableFutureProcessCameraProvider> cameraProviderFuture =
  ProcessCameraProvider.getInstance(this);
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

//重新綁定之前必須先取消綁定
cameraProvider.unbindAll();

Camera camera = cameraProvider.bindToLifecycle(CameraActivity.this,
  cameraSelector,preview,imageCapture,videoCapture);

OK預覽,照相,錄視頻的配置和綁定到生命周期的工作就完成了

預覽的時候需要顯示到一個View控件上吧,CameraX中提供了一個PreviewView用來顯示預覽畫面。其內(nèi)部封裝了TextureView和SurfaceView,可以根據(jù)不同的模式來選擇其內(nèi)部使用TextureView還是SurfaceView來顯示。

xml中添加PreviewView,并在代碼中將其附加到前面創(chuàng)建出來的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()));

這樣當我們進入該頁面的時候就可以看到相機的預覽效果呢,接下來就是執(zhí)行拍照和錄制的功能了

執(zhí)行拍照錄像

拍照:

//創(chuàng)建圖片保存的文件地址
 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);
 }
  • 調(diào)用ImageCapture的takePicture方法來拍照
  • 傳入一個文件地址用來保存拍好的照片
  • onImageSaved方法是照片已經(jīng)拍好并存好之后的回調(diào)
  • onFileSaved方法中將前面保存的文件添加到媒體中,最后跳轉(zhuǎn)到預覽界面。

錄視頻:

//創(chuàng)建視頻保存的文件地址
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文件用來保存視頻,
  • 錄制完成之后回調(diào)onVideoSaved方法,并返回該文件的實例。
  • 調(diào)用onFileSaved方法將前面保存的文件添加到媒體中,最后跳轉(zhuǎn)到預覽界面。
  • 到達錄制時間的時候,需要調(diào)用videoCapture.stopRecording();方法來停止錄像。

到這里使用CameraX拍照和錄制視頻的功能都能完成了,是不是非常簡單。下面來點題外的,自定義一個View,實現(xiàn)點擊拍照,長按錄像的效果。效果如下:

代碼:

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;
   //是否大于系統(tǒng)設定的最小長按時間
   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();
 }
}

實現(xiàn)起來也非常簡單,首先繪制一個圓,監(jiān)聽該View的點擊和長按事件,長按的時候在根據(jù)總錄制時長和當前錄制時間算出需要繪制的角度,就可以在圓上面繪制進度了。

最后通過接口將點擊 長按和錄制完成的事件返回,跟前面的拍照,錄制,錄制完成的代碼結合起來就完成上面的效果了。

CameraView

如果覺得前面的初始化還不夠簡單,那么可以使用CameraX提供的CameraView了,這里面將PreviewView,Preview,ImageCapture,VideoCapture等都封裝起來了,而且還能實現(xiàn)縮放,裁剪,旋轉(zhuǎn)等功能,使用起來更加簡單。

首先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對象來調(diào)用 mCameraView.takePicture , mCameraView.startRecording ,調(diào)用之前需要通過 mCameraView.setCaptureMode(CameraView.CaptureMode.IMAGE) 來切換當前的模式是拍照還是錄像。

將前面的自定義的RecordView加入布局文件中,跟CameraView的拍照、錄像代碼一結合,很快就能實現(xiàn)跟前面一樣的效果了。

圖片分析

CameraX還提供了圖像分析功能,它提供了可供 CPU 訪問以執(zhí)行圖像處理、計算機視覺或機器學習推斷的圖像,可以無縫的訪問緩沖區(qū),一般用不到但功能很強大。創(chuàng)建一個圖片分析器然后綁定聲明周期即可。

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,可以直接對接手機產(chǎn)商,如果該手機廠商實現(xiàn)了CameraX的擴展程序,就可以使用VamerX的擴展API直接調(diào)用這些效果比如:美顏、DHR、夜間、自動等模式。

因為不是所有的手機廠商都支持擴展程序,所以在使用擴展的時候需要判斷一下該手機是否支持,支持才添加。

給預覽界面設置外部擴展,需要 Preview.BuilderCameraSelector cameraSelector) 兩個參數(shù)

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) 兩個參數(shù)

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拍照和拍視頻內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • 詳解Android JetPack之LiveData的工作原理
  • Android Jetpack- Paging的使用詳解
  • Android Jetpack架構組件Lifecycle詳解
  • Android Jetpack架構組件 ViewModel詳解
  • Android Jetpack中Room的使用

標簽:臺州 平頂山 綿陽 商丘 鎮(zhèn)江 鶴崗 株洲 哈密

巨人網(wǎng)絡通訊聲明:本文標題《JetPack開發(fā)中使用CameraX完成拍照和拍視頻功能》,本文關鍵詞  JetPack,開發(fā),中,使用,CameraX,;如發(fā)現(xiàn)本文內(nèi)容存在版權問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《JetPack開發(fā)中使用CameraX完成拍照和拍視頻功能》相關的同類信息!
  • 本頁收集關于JetPack開發(fā)中使用CameraX完成拍照和拍視頻功能的相關信息資訊供網(wǎng)民參考!
  • 推薦文章