Android 7.1 RK3288 A40i Camera2 拍照镜像分析
https://www.cnblogs.com/Free-Thinker/p/6394797.html Android入门——Bitmap和BitmapFactory
要求:Camera2 拍照 镜像
主要的想法: 是根据 拍照按钮来跟踪成像照片 最后镜像翻转
Rk3288 PhotoModule 模式
A40i CaptureModule 模式 ,改缩略图 改成像图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ==================================================== 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | ===================================================== 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 默认镜像 改法
一.开日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | --- 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 缩略图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | --- 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 成像工具类 中改成像图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | --- 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, |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步