Android 7.1 Camera2 拍照镜像分析
作者:互联网
要求: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); }
标签:7.1,java,camera,Camera2,public,session,Android,android 来源: https://www.cnblogs.com/crushgirl/p/14311734.html