android - Camera2 控制连拍模式
问题描述
因此,我们正在尝试制作一个在您旋转设备时(大约每 3 个角度)拍摄照片的应用程序。但是,当我们旋转设备时,使用 camera2:
- 每次拍照,预览都会滞后
- 几张图片后,onCaptureFailed 触发,代码为 0
我仍在尝试找出Camera2(似乎很多人认为它超级棒,所以我试图弄清楚它,但它相当复杂)。我下载了 RAW 示例 ( https://github.com/googlesamples/android-Camera2Raw ) 并对其进行了修改以按上述方式工作。
以前,我们使用过时的相机 api,它在三星 s8 上 100% 工作 - 但在旧设备上失败,因为拍摄图像的速度太快而无法处理。但是,我看到这些旧设备实际上确实允许拍摄 BURST 照片 - 所以相机 2 肯定允许人们以某种方式访问此功能吗?
需要说明的是:我不想拍摄连拍照片,因为这会导致在角度尚未改变的情况下拍摄图像。这是我需要更改的代码:
// Gets called whenever the sensor gives me a value. calculates if it is time to take the next photo
private void updateAngle(double angle) {
mCurrentAngle = angle;
double photoAngle = angle - mOffset < 0 ? CONST_360 + angle - mOffset : angle - mOffset;
if (photoAngle < mPrevAngle) {
tvZAxis.setText("You are going the wrong way");
Log.w("BROKEN", mPrevAngle + " " + photoAngle);
return;
}
if (mStart) {
double diff = photoAngle - mPrevAngle;
if (diff > 300) {
tvZAxis.setText("You have gone the wrong way. ");
return;
}
if (diff > MAX_ALLOWED_ANGLE) {
tvZAxis.setText("You are going too fast, go back a bit");
return;
} else if (diff > 1) {
if (diff >= 3) {
tvZAxis.setText("Do not go faster");
}
if (photoAngle > 356 && diff < 7) {
photoAngle = CONST_360;
}
mPrevAngle = photoAngle;
int prog = Math.max(0, (int) ((photoAngle / CONST_360) * 100.f));
mProgress = prog;
mProgressBar.setProgress(Math.max(0, prog));
takePicture();
// We USED to use old camer API: mCamera.takePicture(null, null, mPicture);
}
}
}
而回调,我只是更改了文件名,以便能够区分每张有角度的照片:
/**
* A {@link CameraCaptureSession.CaptureCallback} that handles the still JPEG and RAW capture
* request.
*/
private final CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
long timestamp, long frameNumber) {
mPhotoCount++;
String currentDateTime = generateTimestamp();
File rawFile = new File(Environment.
getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
"RAW_" + mPhotoCount + ".dng");
File jpegFile = new File(Environment.
getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
"JPEG_" + mPhotoCount + ".jpg");
// Look up the ImageSaverBuilder for this request and update it with the file name
// based on the capture start time.
ImageSaver.ImageSaverBuilder jpegBuilder;
ImageSaver.ImageSaverBuilder rawBuilder;
int requestId = (int) request.getTag();
synchronized (mCameraStateLock) {
jpegBuilder = mJpegResultQueue.get(requestId);
rawBuilder = mRawResultQueue.get(requestId);
}
if (jpegBuilder != null) jpegBuilder.setFile(jpegFile);
if (rawBuilder != null) rawBuilder.setFile(rawFile);
}
而且,为了更好地衡量,这里是 takePicture() 方法。
/**
* Initiate a still image capture.
* <p/>
* This function sends a capture request that initiates a pre-capture sequence in our state
* machine that waits for auto-focus to finish, ending in a "locked" state where the lens is no
* longer moving, waits for auto-exposure to choose a good exposure value, and waits for
* auto-white-balance to converge.
*/
private void takePicture() {
synchronized (mCameraStateLock) {
mPendingUserCaptures++;
// If we already triggered a pre-capture sequence, or are in a state where we cannot
// do this, return immediately.
if (mState != STATE_PREVIEW) {
return;
}
try {
// Trigger an auto-focus run if camera is capable. If the camera is already focused,
// this should do nothing.
if (!mNoAFRun) {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_START);
}
// If this is not a legacy device, we can also trigger an auto-exposure metering
// run.
if (!isLegacyLocked()) {
// Tell the camera to lock focus.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START);
}
// Update state machine to wait for auto-focus, auto-exposure, and
// auto-white-balance (aka. "3A") to converge.
mState = STATE_WAITING_FOR_3A_CONVERGENCE;
// Start a timer for the pre-capture sequence.
startTimerLocked();
// Replace the existing repeating request with one with updated 3A triggers.
mCaptureSession.capture(mPreviewRequestBuilder.build(), mPreCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
我觉得我错过了一些非常明显的东西。将在我前进的过程中更新帖子(希望是解决方案)。
编辑:好的,自从提出这个问题以来,已经发生了一些重大变化。它现在主要工作 - 但是,取决于设备,它有时会随着设备尝试聚焦而模糊。
TakePicture 已被替换为:
private void captureStillPictureLocked() {
try {
if (null == mCameraDevice) {
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
captureBuilder.addTarget(mJpegImageReader.get().getSurface());
// Use the same AE and AF modes as the preview.
setup3AControlsLocked(captureBuilder);
// Set orientation.
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
sensorToDeviceRotation(mCharacteristics, rotation));
// Set request tag to easily track results in callbacks.
captureBuilder.setTag(mRequestCounter.getAndIncrement());
CaptureRequest request = captureBuilder.build();
// Create an ImageSaverBuilder in which to collect results, and add it to the queue
// of active requests.
ImageSaver.ImageSaverBuilder jpegBuilder = new ImageSaver.ImageSaverBuilder(this)
.setCharacteristics(mCharacteristics);
mJpegResultQueue.put((int) request.getTag(), jpegBuilder);
mCaptureSession.capture(request, mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
和
private final CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
long timestamp, long frameNumber) {
mPhotoCount++;
File jpegFile = new File(Environment.
getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
"JPEG_" + mPhotoCount + ".jpg");
vals.add(jpegFile.getAbsolutePath());
// Look up the ImageSaverBuilder for this request and update it with the file name
// based on the capture start time.
ImageSaver.ImageSaverBuilder jpegBuilder;
int requestId = (int) request.getTag();
synchronized (mCameraStateLock) {
jpegBuilder = mJpegResultQueue.get(requestId);
}
if (jpegBuilder != null) jpegBuilder.setFile(jpegFile);
}
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
TotalCaptureResult result) {
int requestId = (int) request.getTag();
ImageSaver.ImageSaverBuilder jpegBuilder;
StringBuilder sb = new StringBuilder();
// Look up the ImageSaverBuilder for this request and update it with the CaptureResult
synchronized (mCameraStateLock) {
jpegBuilder = mJpegResultQueue.get(requestId);
if (jpegBuilder != null) {
jpegBuilder.setResult(result);
sb.append("Saving JPEG as: ");
sb.append(jpegBuilder.getSaveLocation());
}
// If we have all the results necessary, save the image to a file in the background.
handleCompletionLocked(requestId, jpegBuilder, mJpegResultQueue);
}
if (mProgress >= 100) {
Intent returnData = new Intent();
returnData.putExtra("photoAmount", mPhotoCount);
returnData.putExtra("paths", vals);
setResult(RESULT_OK,returnData);
finish();
}
}
@Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
CaptureFailure failure) {
int requestId = (int) request.getTag();
synchronized (mCameraStateLock) {
mJpegResultQueue.remove(requestId);
}
}
};
老实说,虽然我不得不把它放在次要位置上一段时间。一旦我回到这个问题上会更新这个问题(因为我已经忘记了一切都是做什么的:(),希望到那时我已经自己弄清楚了并且可以发布一个解决方案!
解决方案
推荐阅读
- vb.net - 如何使用 TextBox 和 ComboBox 过滤 ListView?
- python - 如何在不导入 os 模块的情况下找到我们正在使用的操作系统?
- python - 我是 python 新手。我尝试运行一个简单的 while 循环,但收到语法错误
- cuda - 推力::合并在内部使用哪种算法?
- html - Google Fonts API / 优化您的字体请求不起作用
- arrays - 在 Swift 中用相同的值分组一周中的几天
- c - 为什么第二个while循环不运行?
- php - 从带有 www 的文本中提取 url - PHP
- javascript - function that remove duplicates in array, javascript
- django - 在 DetailView 中显示选中和未选中的 ManyToMany 选项