Android 7.1 RK3288 A40i Camera2 拍照镜像分析

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

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

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

K:\ZK-Rxxx_7.1_RK3288_Firmware\ZK_RXXX_RK3288_ANDROID7.1\packages\apps\Camera2\src\com\android\camera\PhotoModule.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:\ZK_A40X_A40i_ANDROID7.1\android\packages\apps\Camera2\src\com\android\camera\CaptureModule.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:\ZK_A40X_A40i_ANDROID7.1\android\packages\apps\Camera2\src\com\android\camera\CaptureModule.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:\ZK_A40X_A40i_ANDROID7.1\android\packages\apps\Camera2\src\com\android\camera\one\OneCamera.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:\ZK_A40X_A40i_ANDROID7.1\android\packages\apps\Camera2\src\com\android\camera\one\v2\photo\PictureTaker.java
public interface PictureTaker {
    /**
     * @See {@link OneCamera#takePicture}
     */
    public void takePicture(OneCamera.PhotoCaptureParameters params, CaptureSession session);
}
		
1.5. PictureTakerImpl类 实现 PictureTaker接口 重写了takePicture方法,
K:\ZK_A40X_A40i_ANDROID7.1\android\packages\apps\Camera2\src\com\android\camera\one\v2\photo\PictureTakerImpl.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:\ZK_A40X_A40i_ANDROID7.1\android\packages\apps\Camera2\src\com\android\camera\one\v2\commands\CameraCommandExecutor.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:\ZK_A40X_A40i_ANDROID7.1\android\packages\apps\Camera2\src\com\android\camera\one\v2\photo\SimpleImageCaptureCommand.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:\ZK_A40X_A40i_ANDROID7.1\android\packages\apps\Camera2\src\com\android\camera\one\v2\imagesaver\JpegImageBackendImageSaver.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;
-        }
+        }*/
     }

 二.A40i 缩略图 

--- a/packages/apps/Camera2/src/com/android/camera/one/v2/imagesaver/JpegImageBackendImageSaver.java
+++ b/packages/apps/Camera2/src/com/android/camera/one/v2/imagesaver/JpegImageBackendImageSaver.java
@@ -48,6 +48,18 @@ import java.util.concurrent.Executors;
 import javax.annotation.Nonnull;
 import javax.annotation.ParametersAreNonnullByDefault;
 
+import android.graphics.Matrix;
+import android.graphics.BitmapFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+
+import android.os.SystemProperties;
+
 /**
  * Wires up the ImageBackend task submission process to save JPEG images. Camera
  * delivers a JPEG-compressed full-size image. This class does very little work
@@ -74,6 +86,7 @@ public class JpegImageBackendImageSaver implements ImageSaver.Builder {
         @Override
         public void saveAndCloseImage(ImageProxy image, Optional<ImageProxy> thumbnail,
                 ListenableFuture<TotalCaptureResultProxy> metadata) {
+				android.util.Log.d("gatsby", "JpegImageBackendImageSaver.saveAndCloseImage()");
             // TODO: Use thumbnail to speed up RGB thumbnail creation whenever
             // possible. For now, just close it.
             if (thumbnail.isPresent()) {
@@ -132,12 +145,97 @@ public class JpegImageBackendImageSaver implements ImageSaver.Builder {
                 // 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);
+				
+				saveBimap(bitmap);
+				
+				String savePicturePath = "storage/emulated/0/gatsby.jpg";				
+				String savePicturePath2 = "storage/emulated/0/gatsby2.jpg";
+				File savePictureFile2 = new File("/storage/emulated/0/gatsby2.jpg");
+											
+				Bitmap rawBitmap = BitmapFactory.decodeFile(savePicturePath);
+				Matrix matrix = new Matrix();
+				matrix.postScale(-1, 1);
+				rawBitmap = Bitmap.createBitmap(rawBitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+				try{
+					FileOutputStream fileOutputStream = new FileOutputStream(savePictureFile2);
+					rawBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
+					fileOutputStream.flush();
+					fileOutputStream.close();
+				} catch (Exception e){
+					e.printStackTrace();
+				}
+							
+				Bitmap rawBitmap2 = BitmapFactory.decodeFile(savePicturePath2);
+							
+                mSession.updateCaptureIndicatorThumbnail(rawBitmap2, rotation);
                 // Send image to remote devices
                 mPictureSaverCallback.onRemoteThumbnailAvailable(payload.data);
+				RootCommand("rm -rf storage/emulated/0/gatsby.jpg");
+				RootCommand("rm -rf storage/emulated/0/gatsby2.jpg");
             }
+        }
+
 
+
+        public static void saveBimap(Bitmap bitmap) {
+	    		
+           String savePicturePath = "storage/emulated/0/gatsby.jpg";
+           File file = new File(savePicturePath);
+            if(!file.exists()){
+                try {
+                    file.createNewFile();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            try {
+                FileOutputStream out = new FileOutputStream(file);
+                if (bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)) {
+                    out.flush();
+                    out.close();
+                }
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+	    
         }
+			
+        private void RootCommand(String cmd) {
+			android.util.Log.d("gatsby", "JpegImageBackendImageSaver.RootCommand");
+            Process process = null;
+            DataOutputStream os = null;
+            DataInputStream is = null;
+            try {
+                process = Runtime.getRuntime().exec("/system/xbin/su");
+                os = new DataOutputStream(process.getOutputStream());
+                os.writeBytes(cmd + "\n");
+                os.writeBytes("exit\n");
+                os.flush();
+	    
+                int aa = process.waitFor();
+                is = new DataInputStream(process.getInputStream());
+	    
+                byte[] buffer = new byte[is.available()];
+                is.read(buffer);
+	    
+                String out = new String(buffer);
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                try {
+                    if (os != null) {
+                        os.close();
+                    }
+                    if (is != null) {
+                        is.close();
+                    }
+                    process.destroy();
+                } catch (Exception e) {
+                }
+            }
+        }		
 
         @Override
         public void onResultUncompressed(TaskImageContainer.TaskInfo task,

 三.A40i 成像工具类 中改成像图

--- a/packages/apps/Camera2/src/com/android/camera/data/PhotoDataFactory.java
+++ b/packages/apps/Camera2/src/com/android/camera/data/PhotoDataFactory.java
@@ -26,6 +26,13 @@ import com.android.camera.util.Size;
 
 import java.util.Date;
 
+import android.graphics.Matrix;
+import android.graphics.BitmapFactory;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
 public class PhotoDataFactory {
     private static final Log.Tag TAG = new Log.Tag("PhotoDataFact");
 
@@ -68,6 +75,27 @@ public class PhotoDataFactory {
         Location location = Location.from(latitude, longitude);
 
         Uri uri = PhotoDataQuery.CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
+		
+		File filePhotoDataPath = new File(filePath);
+		android.util.Log.d("gatsby", "PhotoDataFactory.filePhotoDataPath");
+		Bitmap rawBitmap = BitmapFactory.decodeFile(filePath);
+		Matrix matrix = new Matrix();
+		matrix.postScale(-1, 1);
+		rawBitmap = Bitmap.createBitmap(rawBitmap, 0, 0, rawBitmap.getWidth(), rawBitmap.getHeight(), matrix, true);
+		try {
+			FileOutputStream fileOutputStream = new FileOutputStream(filePhotoDataPath);
+			rawBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
+			fileOutputStream.flush();
+			fileOutputStream.close();
+		} catch (Exception e){
+			e.printStackTrace();
+		}
+		
+		try {
+			Thread.sleep(300);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}		
 
         return new FilmstripItemData(
               id,

  

 

posted @ 2021-01-22 09:59  CrushGirl  阅读(1566)  评论(0编辑  收藏  举报