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,

浙公网安备 33010602011771号