操纵安卓相机的深度图导致应用程序崩溃



试图通过android的camera2 api访问TOF相机生成的深度图,但是当我复制深度图时,应用程序总是崩溃。

  • 安卓操作系统 : 10
  • 安卓 API : 28
  • 拱门 : ARMv8A
  • Qt版本:Felgo 3.6.0
  • 开发于 : 视窗 10 64 位
  • NDK : R18B
  • 电话 : MATE30

错误消息 :F libc : 致命信号 11 (SIGSEGV(,代码 2 (SEGV_ACCERR(,TID 31512 (ImageReader-480( 中的故障地址0x741c259980,pid 31412 (P.Androidndkcam(

查找后置摄像头支撑深度16

std::tuple<std::string, bool> get_camera_depth_id(ACameraManager *cam_manager, int camera_facing)
{
auto camera_ids = get_camera_id_list(cam_manager);
if(camera_ids){
qInfo()<<__func__<<": found camera count "<<camera_ids->numCameras;
for(int i = 0; i < camera_ids->numCameras; ++i){
const char *id = camera_ids->cameraIds[i];
camera_status_t ret = ACAMERA_OK;
auto chars = get_camera_characteristics(cam_manager, id, &ret);
if(ret != ACAMERA_OK){
qInfo()<<__func__<<": cannot obtain characteristics of camera id = "<<id;
continue;
}
auto const entry = get_camera_capabilities(chars.get(), &ret);
if(ret != ACAMERA_OK){
qInfo()<<__func__<<": cannot obtain capabilities of camera id = "<<id;
continue;
}
ACameraMetadata_const_entry lens_info;
ACameraMetadata_getConstEntry(chars.get(), ACAMERA_LENS_FACING, &lens_info);
auto const facing = static_cast<acamera_metadata_enum_android_lens_facing_t>(lens_info.data.u8[i]);
bool is_right_face = facing == camera_facing;
bool support_bc = false, support_depth = false;
for(uint32_t i = 0; i < entry.count; i++) {
if(entry.data.u8[i] == ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE){
support_bc = true;
}
if(entry.data.u8[i] == ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT){
support_depth = true;
}
}
qInfo()<<__func__<<" support bc = "<<support_bc<<", support depth = "<<support_depth
<<", is right face = "<<is_right_face;
if(is_right_face && support_depth){
qInfo()<<__func__<<": obtain depth camera id = "<<id;
return {id, support_bc};
}
}
}else{
qInfo()<<__func__<<": cannot get depth cam";
}
return {};
}

打开相机

void initCam()
{
qDebug()<<__func__<<": init camera manager";
cameraManager = ACameraManager_create();
qDebug()<<__func__<<": get back facing camera id";
auto [id, support_bc] = get_camera_depth_id(cameraManager, ACAMERA_LENS_FACING_BACK);
//auto const id = get_camera_id(cameraManager, ACAMERA_LENS_FACING_BACK);
qInfo()<<__func__<<": back camera id = "<<id.c_str();
if(!id.empty()){
auto const cam_status =
ACameraManager_openCamera(cameraManager, id.c_str(), &cameraDeviceCallbacks, &cameraDevice);
qInfo()<<__func__<<" cam status = "<<cam_status;
qDebug()<<__func__<<": open camera";
android_cam_info cam_info(*cameraManager, id.c_str());
qInfo()<<__func__<<" print depth stream configuration info";
//print the format, width, height, is input information
cam_info.stream_config(ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS).print();
//obtain minimum widh and height for the depth map
std::tie(width_, height_) =
cam_info.stream_config(ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS).get_minimum_dimension();
imageReader = createJpegReader();
if(imageReader){
imageWindow = createSurface(imageReader);
ANativeWindow_acquire(imageWindow);
ACameraDevice_createCaptureRequest(cameraDevice, TEMPLATE_PREVIEW, &request);
ACameraOutputTarget_create(imageWindow, &imageTarget);
ACaptureRequest_addTarget(request, imageTarget);
ACaptureSessionOutput_create(imageWindow, &imageOutput);
ACaptureSessionOutputContainer_create(&outputs);
ACaptureSessionOutputContainer_add(outputs, imageOutput);
ACameraDevice_createCaptureSession(cameraDevice, outputs, &sessionStateCallbacks, &textureSession);
// Start capturing continuously
ACameraCaptureSession_setRepeatingRequest(textureSession, &captureCallbacks, 1, &request, nullptr);
}
}
}

我创建图像阅读器的方式

AImageReader* createJpegReader()
{
AImageReader* reader = nullptr;
media_status_t status = AImageReader_new(width_, height_, AIMAGE_FORMAT_DEPTH16, 1, &reader);
if(status != AMEDIA_OK){
qInfo()<<__func__<<": cannot create AImageReader, error code is = "<<status;
return nullptr;
}
AImageReader_ImageListener listener;
listener.context = this;
listener.onImageAvailable = imageCallback;
AImageReader_setImageListener(reader, &listener);
return reader;
}

创建曲面

ANativeWindow* createSurface(AImageReader* reader)
{
ANativeWindow *nativeWindow;
AImageReader_getWindow(reader, &nativeWindow);
return nativeWindow;
}

AImageReader的回调

static void process_depth_16(void* context, AImage *image)
{
uint16_t *data = nullptr;
int len = 0;
auto const status = AImage_getPlaneData(image, 0, reinterpret_cast<uint8_t**>(&data), &len);
if(status != AMEDIA_OK){
qInfo()<<__func__<<": AImage_getPlaneData fail, error code = "<<status;
return;
}
qInfo()<<__func__<<": image len = "<<len;
auto *impl = static_cast<pimpl*>(context);
convert_depth_16_to_cvmat(data, impl->width_, impl->height_);
}
static void imageCallback(void* context, AImageReader* reader)
{
qDebug()<<__func__;
int status = -1;
auto image = get_next_image(reader, &status);
if(status != AMEDIA_OK){
qInfo()<<__func__<<": cannot acquire next image, error code = "<<status;
return;
}
int32_t format = -1;
AImage_getFormat(image.get(), &format);
if(format == AIMAGE_FORMAT_DEPTH16){
process_depth_16(context, image.get());
}else{
qInfo()<<__func__<<": do not support format = "<<format;
}
}

复制深度图(此功能导致应用崩溃(

cv::Mat convert_depth_16_to_cvmat(uint16_t *data, int32_t width, int32_t height)
{
auto *depth_ptr = data;
cv::Mat output(height, width, CV_16U);
for(int32_t row = 0; row != height; ++row){
depth_ptr += width * row;
auto *output_ptr = output.ptr<ushort>(row);
qInfo()<<__func__<<": row = "<<row; //crash when row equal to 27,sometimes over 50 
for(int32_t col = 0; col != width; ++col){
output_ptr[col] = depth_ptr[col];
}
}
return output;
}

我从ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS获得的最小宽度和高度是 480x360。代码有什么问题吗?

其他实用功能放在帕斯特宾。

编辑:数据的长度为345600,这意味着应该有172800(480x360(像素的数据类型uint16_t

我找到了答案,mate30 不支持深度图,但原生 API 并没有告诉我们,也许原生 API 与深度图相关的功能还没有那么成熟。

最新更新