Android 7.1 Camera2 拍照镜像分析

 https://www.cnblogs.com/Free-Thinker/p/6394797.html Android入门——Bitmap和BitmapFactory

要求:Camera2 拍照 镜像
主要的想法: 是根据 拍照按钮来跟踪成像照片 最后镜像翻转
Rk3288 PhotoModule 模式
A40i     CaptureModule 模式 ,改缩略图 改成像图

====================================================
				RK3288 android7.1
====================================================

K:K-Rxxx_7.1_RK3288_FirmwareK_RXXX_RK3288_ANDROID7.1packagesappsCamera2srccomandroidcameraPhotoModule.java
1.1.拍照按钮回调 onShutterButtonClick
    @Override
    public void onShutterButtonClick() {

1.2.找到拍照最后保存照片 saveFinalPhoto 由Matrix 创建矩阵,并水平平移 镜像
 
--- a/packages/apps/Camera2/src/com/android/camera/PhotoModule.java
+++ b/packages/apps/Camera2/src/com/android/camera/PhotoModule.java
@@ -103,7 +103,7 @@ import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Vector;
-
+import android.graphics.Matrix;
 
 public class PhotoModule
         extends CameraModule
@@ -1644,6 +1644,9 @@ public class PhotoModule
 
         void saveFinalPhoto(final byte[] jpegData, NamedEntity name, final ExifInterface exif,
                 CameraProxy camera) {
+					
+			android.util.Log.d("gatsby", "PhotoModule.saveFinalPhoto CameraCaputre");	
+			
             int orientation = Exif.getOrientation(exif);
 
             float zoomValue = 1.0f;
@@ -1714,8 +1717,17 @@ public class PhotoModule
                         exif.setTag(directionRefTag);
                         exif.setTag(directionTag);
                     }
+                    Bitmap bitmap = CameraUtil.makeBitmap(jpegData, exifWidth*exifHeight);
+                    Matrix m = new Matrix();
+                    m.postScale(-1, 1);
+                    bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
+					 byte[] tm_jpegData;
+                    tm_jpegData = baos.toByteArray();										
+					//gatsby
                     getServices().getMediaSaver().addImage(
-                            jpegData, title, date, mLocation, width, height,
+                            tm_jpegData, title, date, mLocation, width, height,
                             orientation, exif, mOnMediaSavedListener);
                 }
                 // Animate capture with real jpeg data instead of a preview

A40i android7.1

=====================================================
			     2021.01.15
======================================================
1.1. 拍照按钮
K:K_A40X_A40i_ANDROID7.1androidpackagesappsCamera2srccomandroidcameraCaptureModule.java

    @Override
    public void onShutterButtonClick() {
			
        if (mCamera == null) {
            return;
        }

        int countDownDuration = mSettingsManager
                .getInteger(SettingsManager.SCOPE_GLOBAL, Keys.KEY_COUNTDOWN_DURATION);
        if (countDownDuration > 0) {
            // Start count down.
            mAppController.getCameraAppUI().transitionToCancel();
            mAppController.getCameraAppUI().hideModeOptions();
            mUI.setCountdownFinishedListener(this);
            mUI.startCountdown(countDownDuration);
            // Will take picture later via listener callback.
        } else {
            takePictureNow();
        }
    }
1.2. 拍照
K:K_A40X_A40i_ANDROID7.1androidpackagesappsCamera2srccomandroidcameraCaptureModule.java

    private void takePictureNow() {
        if (mCamera == null) {
            Log.i(TAG, "Not taking picture since Camera is closed.");
            return;
        }
		android.util.Log.d("gatsby", "CaptureModule takePictureNow");	
		
        CaptureSession session = createAndStartCaptureSession();
        int orientation = mAppController.getOrientationManager().getDeviceOrientation()
                .getDegrees();

        // TODO: This should really not use getExternalCacheDir and instead use
        // the SessionStorage API. Need to sync with gcam if that's OK.
        PhotoCaptureParameters params = new PhotoCaptureParameters(
                session.getTitle(), orientation, session.getLocation(),
                mContext.getExternalCacheDir(), this, mPictureSaverCallback,
                mHeadingSensor.getCurrentHeading(), mZoomValue, 0);
        decorateSessionAtCaptureTime(session);
		//gatsby take a pircture
        mCamera.takePicture(params, session);
    }
	
1.3
K:K_A40X_A40i_ANDROID7.1androidpackagesappsCamera2srccomandroidcameraoneOneCamera.java
		
    /**
     * Call this to take a picture.
     *
     * @param params parameters for taking pictures.
     * @param session the capture session for this picture.
     */
    public void takePicture(PhotoCaptureParameters params, CaptureSession session);		
		

1.4. 定义PictureTaker接口
K:K_A40X_A40i_ANDROID7.1androidpackagesappsCamera2srccomandroidcameraonev2photoPictureTaker.java
public interface PictureTaker {
    /**
     * @See {@link OneCamera#takePicture}
     */
    public void takePicture(OneCamera.PhotoCaptureParameters params, CaptureSession session);
}
		
1.5. PictureTakerImpl类 实现 PictureTaker接口 重写了takePicture方法,
K:K_A40X_A40i_ANDROID7.1androidpackagesappsCamera2srccomandroidcameraonev2photoPictureTakerImpl.java

	class PictureTakerImpl implements PictureTaker {
		
    @Override
    public void takePicture(OneCamera.PhotoCaptureParameters params, final CaptureSession session) {
		android.util.Log.d("gatsby", "PictureTakerImpl  takePicture");
        OneCamera.PictureCallback pictureCallback = params.callback;

        // Wrap the pictureCallback with a thread-safe adapter which guarantees
        // that they are always invoked on the main thread.
        PictureCallbackAdapter pictureCallbackAdapter =
                new PictureCallbackAdapter(pictureCallback, mMainExecutor);

        final Updatable<Void> imageExposureCallback =
                pictureCallbackAdapter.provideQuickExposeUpdatable();

        final ImageSaver imageSaver = mImageSaverBuilder.build(
                params.saverCallback,
                OrientationManager.DeviceOrientation.from(params.orientation),
                session);
		//Log future
        mCameraCommandExecutor.execute(new PictureTakerCommand(
                imageExposureCallback, imageSaver, session));
    }
		
1.6. Executing command
gatsby  (13557): Executing command: PictureTakerCommand{command=com.android.camera.one.v2.photo.SimpleImageCaptureCommand@d754686} START
K:K_A40X_A40i_ANDROID7.1androidpackagesappsCamera2srccomandroidcameraonev2commandsCameraCommandExecutor.java
    public Future<?> execute(CameraCommand command) {
        if (mClosed) {
            return Futures.immediateFuture(null);
        }
        synchronized (mLock) {
            if (mExecutor == null) {
                // Create a new executor, if necessary.
                mExecutor = mExecutorProvider.get();
            }
            checkNotNull(mExecutor);
			android.util.Log.d("gatsby", "CameraCommandExecutor Future<?> checkNotNull(mExecutor)"+new CommandRunnable(command));
            return mExecutor.submit(new CommandRunnable(command));
        }
    }

1.7. 发送拍照请求  (走到这里断了,研究ing)
https://blog.csdn.net/afei__/article/details/86326991 
a.CaptureRequest 表示一个捕捉的请求。根据不同的场景(预览、拍照)创建不同的捕捉请求,并可以配置不同的捕捉属性,如:
预览分辨率,预览目标,对焦模式、曝光模式等等
b.CaptureRequest.Builder TEMPLATE_STILL_CAPTURE : 用于创建一个拍照请求。相机会优先保证高画质而不是高帧率。适用于所有相机设备

K:K_A40X_A40i_ANDROID7.1androidpackagesappsCamera2srccomandroidcameraonev2photoSimpleImageCaptureCommand.java
    /**
     * Sends a request to take a picture and blocks until it completes.
     */
	 //发送一个拍照请求并阻塞直到它完成
    @Override
    public void run(Updatable<Void> imageExposureUpdatable, ImageSaver imageSaver) throws
            InterruptedException, CameraAccessException, CameraCaptureSessionClosedException,
            ResourceAcquisitionFailedException {
        try (FrameServer.Session session = mFrameServer.createExclusiveSession();
                ImageStream imageStream = mImageReader.createStream(1)) {
			android.util.Log.d("gatsby", "SimpleImageCaptureCommand  run");
            UpdatableCountDownLatch<Void> exposureLatch = new UpdatableCountDownLatch<>(1);
            RequestBuilder photoRequest = mBuilderFactory.create(CameraDevice
                    .TEMPLATE_STILL_CAPTURE);
            photoRequest.addStream(imageStream);
            MetadataFuture metadataFuture = new MetadataFuture();
            photoRequest.addResponseListener(metadataFuture);
            photoRequest.addResponseListener(forFrameExposure(imageExposureUpdatable));
            photoRequest.addResponseListener(forFrameExposure(exposureLatch));
            session.submitRequest(Arrays.asList(photoRequest.build()),
                    FrameServer.RequestType.NON_REPEATING);

            // Release the FrameServer session (allowing subsequent camera
            // operations to occur) as soon as the image is exposed.
            exposureLatch.await();
            session.close();

            ImageProxy image = imageStream.getNext();
			//addFullSizeImage 时间戳 拍照尺寸
            imageSaver.addFullSizeImage(image, metadataFuture.getMetadata());
        } catch (BufferQueue.BufferQueueClosedException e) {
            // If we get here, the request was submitted, but the image
            // never arrived.
            // TODO Log failure and notify the caller
        } finally {
            imageSaver.close();
        }
    }
	
1.7.1 获取照片 时间戳、尺寸

01-01 20:16:33.927  3321  3882 D gatsby  : MostRecentImageSaver  addFullSizeImage333->MetadataImage{timestamp=994912780557, width=1280, height=960}

    @Override
    public void addFullSizeImage(ImageProxy imageProxy,
            ListenableFuture<TotalCaptureResultProxy> metadata) {
        mFullSizeImages.put(imageProxy.getTimestamp(), new MetadataImage(imageProxy, metadata));
        closeOlderImages();
    }

1.8.重新回到 PictureTakerImpl 这里来 ,JpegImageBackendImageSaver.java 缩略图

	        final ImageSaver imageSaver = mImageSaverBuilder.build(
                params.saverCallback,
                OrientationManager.DeviceOrientation.from(params.orientation),
                session);
	
K:K_A40X_A40i_ANDROID7.1androidpackagesappsCamera2srccomandroidcameraonev2imagesaverJpegImageBackendImageSaver.java
public class JpegImageBackendImageSaver implements ImageSaver.Builder {
	    @Override
        public void onResultCompressed(TaskImageContainer.TaskInfo task,
                TaskImageContainer.CompressedPayload payload) {
            if (task.destination == TaskImageContainer.TaskInfo.Destination.FINAL_IMAGE) {
                // Just start the thumbnail now, since there's no earlier event.

                // Downsample and convert the JPEG payload to a reasonably-sized
                // Bitmap
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = JPEG_DOWNSAMPLE_FOR_FAST_INDICATOR;
				//gatsby payload.data  获得data
                final Bitmap bitmap = BitmapFactory.decodeByteArray(payload.data, 0,
                        payload.data.length, options);

                // If the rotation is implemented as an EXIF flag, we need to
                // pass this information onto the UI call, since the rotation is
                // NOT applied to the bitmap directly.
                int rotation = Exif.getOrientation(payload.data);
                mSession.updateCaptureIndicatorThumbnail(bitmap, rotation);
                // Send image to remote devices
                mPictureSaverCallback.onRemoteThumbnailAvailable(payload.data);
            }

 A40i  Camera2 默认镜像 改法

一.开日志

--- a/packages/apps/Camera2/src/com/android/camera/debug/Log.java
+++ b/packages/apps/Camera2/src/com/android/camera/debug/Log.java
@@ -192,7 +192,10 @@ public class Log {
     }
 
     private static boolean isLoggable(Tag tag, int level) {
-        if (sSuppressForTesting) {
+		
+		return true;
+		
+       /* if (sSuppressForTesting) {
             return false;
         }
         try {
@@ -208,7 +211,7 @@ public class Log {
         } catch (IllegalArgumentException ex) {
             e(TAG, "Tag too long:" + tag);
             return false;
-        }
+        }*/
     }

 二.预览图

  

 

  

原文地址:https://www.cnblogs.com/crushgirl/p/14311734.html