ImageSaver 中传递给 DngSaver 的 CaptureResult 为 null camera2 api
CaptureResult passed to DngSaver in ImageSaver is null camera2 api
在尝试使用 camera2api 构建相机应用程序的过程中,我在尝试保存原始图像时遇到了一个小问题。
我在下面的代码中将捕获结果分配给成员。
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
mCaptureResult = result;
Toast.makeText(getApplicationContext(),
"Image Captured",Toast.LENGTH_SHORT).show();
}
};
当我在这个位置调试它时,成员被分配而不是 null。但是,当它在 ImageSaver
class.
中的 DngCreator
处抛出空错误时
我的听众:
private ImageReader mImageReader;
private ImageReader.OnImageAvailableListener mOnImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
mBackgroundHandler.post(new ImageSaver(imageReader.acquireNextImage(),mUiHandler,
mCaptureResult, mCameraCharacteristics));
}
};
private ImageReader mRawImageReader;
private ImageReader.OnImageAvailableListener mOnRawImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
mBackgroundHandler.post(new ImageSaver(imageReader.acquireNextImage(),mUiHandler,
mCaptureResult, mCameraCharacteristics));
}
};
我的图像保护程序class:
private ImageSaver(Image image, Handler handler, CaptureResult captureResult,
CameraCharacteristics cameraCharacteristics) {
mImage = image;
mHandler =handler;
mCaptureResult = captureResult;
mCameraCharacteristics = cameraCharacteristics;
}
@Override
public void run() {
int format = mImage.getFormat();
switch(format){
case ImageFormat.JPEG:
ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(mImageFile);
fileOutputStream.write(bytes);
}
catch (IOException e){
e.printStackTrace();
}
finally {
mImage.close();
if(fileOutputStream != null){
try{
fileOutputStream.close();
}
catch (IOException e){
e.printStackTrace();
}
}
//Message message = mHandler.obtainMessage();
//message.sendToTarget();
}
break;
case ImageFormat.RAW_SENSOR:
DngCreator dngCreator = new DngCreator(mCameraCharacteristics,mCaptureResult);
FileOutputStream rawFileOutputStream = null;
try {
rawFileOutputStream = new FileOutputStream(mRawImageFile);
dngCreator.writeImage(rawFileOutputStream, mImage);
}
catch (IOException e){
e.printStackTrace();
}
finally{
mImage.close();
if(rawFileOutputStream != null){
try {
rawFileOutputStream.close();
}
catch (IOException e){
e.printStackTrace();
}
}
}
break;
}
}
}
现在,当我尝试初始化 DngCreator 时出现错误,堆栈跟踪如下。
FATAL EXCEPTION: Camera2 Background Thread
Process: com.something.something, PID: 5162
java.lang.IllegalArgumentException: Null argument to DngCreator constructor
at android.hardware.camera2.DngCreator.<init>(DngCreator.java:89)
at com.something.something.ControlCameraActivity$ImageSaver.run(ControlCameraActivity.java:328)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
有人可以帮我解决这个问题吗?如果您需要我提供更多信息,请立即联系我。谢谢
不能保证 onCaptureCompleted() 在 OnImageAvailable() 之前发生。事实上,由于 RAW 图像缓冲区通常比预览和结果元数据的图像处理完成更早准备就绪,因此 onCaptureCompleted() 很可能在 onImageAvailable() 之后发生。
如果先发生 onImageAvailable,则您还没有捕获结果。
相反,您应该等待图像和捕获结果都完成,然后创建 ImageSaver。作为一种选择,让两个回调将各自的输出(捕获结果和图像)保存在某个共享位置,然后检查两者是否非空 - 如果是,则调用 ImageSaver。然后哪个先运行并不重要,第二个运行的启动ImageSaver。
首先,当您调用 imageReader.acquireNextImage()
时,将其设置在 Image 对象中,并在使用后执行 Image.close。 ImageReaders 对于垃圾收集器来说真的很危险,而且如果你的 ImageReader maxImages 中的数字很低,你会很快填充它,因为你没有关闭图像。
其次,关于你的引用,你的 savingImage 方法在哪里? image 不是可解析的对象,因此,如果您将其发送到服务或其他服务 class,您可能遇到了问题。
最后,正如@Eddy 所说,有时不会在您的 OnImageAvailable 之前调用 onCaptureComplete。因此,您有 2 个解决方案:
只需在您的应用中添加一个避免 FC 的检查:
if (mImage != null && mCameraCharacteristics != null && mDngResult != null) {
//process your dng
}
或者,您可以创建一个监听器。因此,当您收到 onImageAvailable()
时,您可以将请愿书放入自定义列表或 Hastable 中。
在那里,检查 List 是否有可用的 captureResult
,如果您有 CaptureResult,获取它并处理您的 DNG,如果没有实例化一个将在您的 onCaptureComplete
中调用的监听器。在那里,您只需要检查侦听器是否为空,如果不是,则在您的结果可用后调用 "process" 图像。
public class MyResultList {
private DngListener mDngListener;
private Hashtable<String, CaptureResult> mDngCaptureResults;
public int getSize() {
return mDngCaptureResults.size();
}
public Object getResult() {
if (mDngCaptureResults.size() == 0){
mDngListener = new DngListener() {
@Override
public void onResultAvailable() {
//Now result is not null, so you can get the available item
YourSavingImage(mDngCaptureResults.get(0));
}
}
return null;
} else {
return mDngCaptureResults.get(0);
}
}
public void add(CaptureResult result, String index){
mDngCaptureResults.put(index,result);
}
}
我只是提出了这个想法,请根据您的目标对其进行修改。它非常简单,如果你有很多依赖项,可能效果不佳。
在尝试使用 camera2api 构建相机应用程序的过程中,我在尝试保存原始图像时遇到了一个小问题。
我在下面的代码中将捕获结果分配给成员。
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
mCaptureResult = result;
Toast.makeText(getApplicationContext(),
"Image Captured",Toast.LENGTH_SHORT).show();
}
};
当我在这个位置调试它时,成员被分配而不是 null。但是,当它在 ImageSaver
class.
DngCreator
处抛出空错误时
我的听众:
private ImageReader mImageReader;
private ImageReader.OnImageAvailableListener mOnImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
mBackgroundHandler.post(new ImageSaver(imageReader.acquireNextImage(),mUiHandler,
mCaptureResult, mCameraCharacteristics));
}
};
private ImageReader mRawImageReader;
private ImageReader.OnImageAvailableListener mOnRawImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
mBackgroundHandler.post(new ImageSaver(imageReader.acquireNextImage(),mUiHandler,
mCaptureResult, mCameraCharacteristics));
}
};
我的图像保护程序class:
private ImageSaver(Image image, Handler handler, CaptureResult captureResult,
CameraCharacteristics cameraCharacteristics) {
mImage = image;
mHandler =handler;
mCaptureResult = captureResult;
mCameraCharacteristics = cameraCharacteristics;
}
@Override
public void run() {
int format = mImage.getFormat();
switch(format){
case ImageFormat.JPEG:
ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(mImageFile);
fileOutputStream.write(bytes);
}
catch (IOException e){
e.printStackTrace();
}
finally {
mImage.close();
if(fileOutputStream != null){
try{
fileOutputStream.close();
}
catch (IOException e){
e.printStackTrace();
}
}
//Message message = mHandler.obtainMessage();
//message.sendToTarget();
}
break;
case ImageFormat.RAW_SENSOR:
DngCreator dngCreator = new DngCreator(mCameraCharacteristics,mCaptureResult);
FileOutputStream rawFileOutputStream = null;
try {
rawFileOutputStream = new FileOutputStream(mRawImageFile);
dngCreator.writeImage(rawFileOutputStream, mImage);
}
catch (IOException e){
e.printStackTrace();
}
finally{
mImage.close();
if(rawFileOutputStream != null){
try {
rawFileOutputStream.close();
}
catch (IOException e){
e.printStackTrace();
}
}
}
break;
}
}
}
现在,当我尝试初始化 DngCreator 时出现错误,堆栈跟踪如下。
FATAL EXCEPTION: Camera2 Background Thread
Process: com.something.something, PID: 5162
java.lang.IllegalArgumentException: Null argument to DngCreator constructor
at android.hardware.camera2.DngCreator.<init>(DngCreator.java:89)
at com.something.something.ControlCameraActivity$ImageSaver.run(ControlCameraActivity.java:328)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
有人可以帮我解决这个问题吗?如果您需要我提供更多信息,请立即联系我。谢谢
不能保证 onCaptureCompleted() 在 OnImageAvailable() 之前发生。事实上,由于 RAW 图像缓冲区通常比预览和结果元数据的图像处理完成更早准备就绪,因此 onCaptureCompleted() 很可能在 onImageAvailable() 之后发生。
如果先发生 onImageAvailable,则您还没有捕获结果。
相反,您应该等待图像和捕获结果都完成,然后创建 ImageSaver。作为一种选择,让两个回调将各自的输出(捕获结果和图像)保存在某个共享位置,然后检查两者是否非空 - 如果是,则调用 ImageSaver。然后哪个先运行并不重要,第二个运行的启动ImageSaver。
首先,当您调用 imageReader.acquireNextImage()
时,将其设置在 Image 对象中,并在使用后执行 Image.close。 ImageReaders 对于垃圾收集器来说真的很危险,而且如果你的 ImageReader maxImages 中的数字很低,你会很快填充它,因为你没有关闭图像。
其次,关于你的引用,你的 savingImage 方法在哪里? image 不是可解析的对象,因此,如果您将其发送到服务或其他服务 class,您可能遇到了问题。
最后,正如@Eddy 所说,有时不会在您的 OnImageAvailable 之前调用 onCaptureComplete。因此,您有 2 个解决方案:
只需在您的应用中添加一个避免 FC 的检查:
if (mImage != null && mCameraCharacteristics != null && mDngResult != null) {
//process your dng
}
或者,您可以创建一个监听器。因此,当您收到 onImageAvailable()
时,您可以将请愿书放入自定义列表或 Hastable 中。
在那里,检查 List 是否有可用的 captureResult
,如果您有 CaptureResult,获取它并处理您的 DNG,如果没有实例化一个将在您的 onCaptureComplete
中调用的监听器。在那里,您只需要检查侦听器是否为空,如果不是,则在您的结果可用后调用 "process" 图像。
public class MyResultList {
private DngListener mDngListener;
private Hashtable<String, CaptureResult> mDngCaptureResults;
public int getSize() {
return mDngCaptureResults.size();
}
public Object getResult() {
if (mDngCaptureResults.size() == 0){
mDngListener = new DngListener() {
@Override
public void onResultAvailable() {
//Now result is not null, so you can get the available item
YourSavingImage(mDngCaptureResults.get(0));
}
}
return null;
} else {
return mDngCaptureResults.get(0);
}
}
public void add(CaptureResult result, String index){
mDngCaptureResults.put(index,result);
}
}
我只是提出了这个想法,请根据您的目标对其进行修改。它非常简单,如果你有很多依赖项,可能效果不佳。