Android Camera2 Burst и ImageReader
Я пытаюсь получить несколько снимков с разным временем экспозиции для HDR algorithm
, Тем не менее, я не могу понять, как использовать captureBurst()
в Android camera2 API
а также ImageReader
сохранить файлы. Мой код будет создавать дубликаты файлов. Кто-нибудь может мне помочь?
private ImageReader mImageReader;
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage()));
}
};
private static class ImageSaver implements Runnable {
private final Image mImage;
private ImageSaver(Image image) {
mImage = image;
}
private File createNewImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "IMG_" + timeStamp;
File storageDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM + "/Camera");
File image = File.createTempFile(imageFileName, ".jpg", storageDirectory);
return image;
}
@Override
public void run() {
ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
FileOutputStream fileOutputStream = null;
try {
File newFile = null;
try {
newFile = createNewImageFile();
} catch (IOException e) {
e.printStackTrace();
}
fileOutputStream = new FileOutputStream(newFile);
fileOutputStream.write(bytes);
mImageFileNameList.add(newFile.getName());
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private void captureStillImage() {
try {
CaptureRequest.Builder captureStillBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureStillBuilder.addTarget(mImageReader.getSurface());
CaptureRequest.Builder captureStillBuilder2 = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureStillBuilder2.addTarget(mImageReader.getSurface());
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureStillBuilder.set(CaptureRequest.JPEG_ORIENTATION,
ORIENTATIONS.get(rotation));
captureStillBuilder2.set(CaptureRequest.JPEG_ORIENTATION,
ORIENTATIONS.get(rotation));
CameraCaptureSession.CaptureCallback captureCallback =
new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
unlockFocus();
}
};
List<CaptureRequest> list = new ArrayList<>();
captureStillBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
captureStillBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
captureStillBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, ONE_SECOND / 100);
captureStillBuilder2.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
captureStillBuilder2.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
captureStillBuilder2.set(CaptureRequest.SENSOR_EXPOSURE_TIME, ONE_SECOND / 20);
list.add(captureStillBuilder.build());
list.add(captureStillBuilder2.build());
mCameraCaptureSession.captureBurst(list, captureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
2 ответа
Если кажется, что все работает иначе, и ваша проблема заключается в дублировании имен файлов, возможно, это связано с тем, что ваш телефон может записывать два JPEG-файла с интервалом более 1 секунды.
Строка формата для имени файла изображения: "yyyyMMdd_HHmmss". Это не включает доли секунды, поэтому снимки, сделанные, скажем, в 12:35:15.100 и 12:35:15.700 (с интервалом 600 мс) будут отображаться с тем же именем файла, IMG_..._123515.jpg.
Вы можете просто добавить "_SSS" к вашей строке, чтобы включить также миллисекунды, согласно документации SimpleDateFormat, которая должна устранять неоднозначность ваших имен файлов, если только они не были захвачены очень быстро.
В качестве альтернативы, вы можете сохранить какой-то счетчик для файлов с одинаковыми именами и добавлять _1, _2 и т. Д. В случае конфликта.
Вот мой код из похожего сценария, где я сохраняю свои файлы в папке с именем C2 во внешней папке Pictures:
@Override
public void onImageAvailable(ImageReader reader) {
String currentDateTime = generateTimestamp();
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()
+ "/C2/" + mCount++ + "_" + currentDateTime + ".jpg");
if (mCount == 3) mCount = 1; // Reset the counter
mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), file));
}
и mCount установлен как
private int mCount = 1;
И generateTimestamp взят из примера кода Google:
/**
* Generate a string containing a formatted timestamp with the current date and time.
*
* @return a {@link String} representing a time.
*/
private static String generateTimestamp() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_SSS", Locale.US);
return sdf.format(new Date());
}