AOSP 13 i.MX8MM开发板NDK Camera2 AImageReader无帧接收问题
在i.MX8MM Var-SOM开发板基于AOSP 13系统,使用NDK Camera2 API实现原生人脸检测,目标是通过AImageReader捕获帧并交给TensorFlow Lite处理。相机能成功打开,但AImageReader始终无法接收帧,持续出现以下日志:
W CameraDeviceSessionHwlImpl: map_frame_request still empty after 100000000 ns
W CameraDeviceSessionHwlImpl: HandleImage: mImageList still empty after 100000000 ns
已验证的操作:
- ✅ 相机成功打开(CameraService::connect日志确认)
- ✅ AImageReader已创建并设置监听器(日志确认)
- ✅ 捕获会话成功启动(日志显示“Capture Session Active”)
- ❌ 无帧传输至ImageReader(“Image Available Callback Triggered!”从未触发)
- ✅ 相机服务日志(
dumpsys media.camera)显示:相机设备已打开,但无帧被处理,提示“No input stream configured.”
相关代码实现:
AImageReader配置及图像回调
// Creating AImageReader AImageReader_new(320, 240, AIMAGE_FORMAT_JPEG, 10, &imageReader); AImageReader_ImageListener listener = { .context = nullptr, .onImageAvailable = ImageCallback }; AImageReader_setImageListener(imageReader, &listener);
图像回调函数
void ImageCallback(void* context, AImageReader* reader) { LOG("Image Available Callback Triggered!"); AImage* image; media_status_t imgStatus = AImageReader_acquireLatestImage(reader, &image); if (imgStatus != AMEDIA_OK || !image) { LOGE("Failed to acquire image, status: %d", imgStatus); return; } int32_t width, height, format; AImage_getWidth(image, &width); AImage_getHeight(image, &height); AImage_getFormat(image, &format); LOG("Received Image: %dx%d, Format: %d", width, height, format); AImage_delete(image); }
捕获请求配置
ACameraDevice_createCaptureRequest(cameraDevice, TEMPLATE_PREVIEW, &captureRequest); // Attach ImageReader to Capture Request ANativeWindow* nativeWindow; AImageReader_getWindow(imageReader, &nativeWindow); ACameraOutputTarget* imageReaderTarget; ACameraOutputTarget_create(nativeWindow, &imageReaderTarget); ACaptureRequest_addTarget(captureRequest, imageReaderTarget); // Set Capture Request Parameters ACaptureRequest_setEntry_i32(captureRequest, ACAMERA_SENSOR_SENSITIVITY, 1, (int32_t[]){400}); ACaptureRequest_setEntry_i32(captureRequest, ACAMERA_CONTROL_AE_TARGET_FPS_RANGE, 2, (int32_t[]){15, 30}); ACaptureRequest_setEntry_i32(captureRequest, ACAMERA_SCALER_CROP_REGION, 4, (int32_t[]){0, 0, 320, 240}); // Start Capture Session camera_status_t cam_status = ACameraCaptureSession_setRepeatingRequest( captureSession, nullptr, 1, &captureRequest, nullptr); if (cam_status != ACAMERA_OK) { LOGE("Failed to start capture session, status: %d", cam_status); return; } LOG("Camera Capture Started!");
更换AImageReader的图像格式
当前使用AIMAGE_FORMAT_JPEG作为预览格式,但多数Android相机硬件的预览流不支持直接输出JPEG格式(JPEG多用于静态拍照)。预览流优先使用标准YUV格式,比如AIMAGE_FORMAT_YUV_420_888,修改AImageReader_new参数:AImageReader_new(320, 240, AIMAGE_FORMAT_YUV_420_888, 10, &imageReader);验证相机支持的流配置
日志中的“No input stream configured.”说明当前设置的分辨率、格式组合不被硬件支持。需要先查询相机支持的输出配置:- 调用
ACameraDevice_getCharacteristics获取相机特性 - 从特性中提取
ACAMERA_SCALER_STREAM_CONFIGURATION_MAP,枚举所有支持的分辨率和格式组合 - 确保320x240和所选格式在支持列表内
- 调用
修正捕获会话的创建流程
必须在创建ACameraCaptureSession时就将AImageReader的NativeWindow作为输出目标传入,而非仅在捕获请求中添加。正确流程:- 创建AImageReader后,获取其NativeWindow
- 将NativeWindow加入会话的输出目标列表
- 调用
ACameraDevice_createCaptureSession创建会话并传入该目标列表 - 会话创建成功后,再创建捕获请求、添加目标并启动重复捕获
移除或验证自定义参数
当前设置的ACAMERA_SCALER_CROP_REGION可能不符合硬件支持的裁剪规则,建议先移除该参数,测试基础流是否正常,再逐步添加其他参数。确保资源正确释放
使用完ACameraOutputTarget后需及时释放,避免资源泄漏导致流异常:ACaptureRequest_removeTarget(captureRequest, imageReaderTarget); ACameraOutputTarget_free(imageReaderTarget);
内容的提问来源于stack exchange,提问作者frostSi

