CameraAPI2 向Camera HAL 传递数据如相机参数主要是通过camera_metadata实现的,最近项目有个需求是向Camera HAL 传递一个YUV数据,大小是几兆左右,使用现有的camera_metadata来实现困难(需要以后研究下其可行性1)。
为实现该功能,进一步提升CameraAPI2 向Camera HAL传递数据的能力,本文通过扩展ICameraProvider.hal接口向CameraProvider进程传递一个匿名共享内存(Ashmem)来实现该功能。
主要实现如下:
修改ICameraProvider.hal文件
//hardware\interfaces\camera\provider\2.4\ICameraProvider.hal
--- a/camera/provider/2.4/ICameraProvider.hal
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -185,4 +185,7 @@ interface ICameraProvider {
(Status status,
android.hardware.camera.device@3.2::ICameraDevice device);
//扩展的接口registerMemory
//descriptor为共享内存句柄
//bufferSize为共享内存大小
//bufferCount共享内存个数
//memId?
+ registerMemory(handle descriptor, uint32_t bufferSize, uint32_t bufferCount)
+ generates (uint32_t memId);
+
};
重新编译下CameraProvider(可能需要修改下hardware\interfaces\current.txt才能编译过2)
--- a/current.txt
+++ b/current.txt
@@ -58,7 +58,6 @@ b32f9aeaf1c442195eb06ffc7600968c919d005b2718874f09c57287fae55918 android.hardwar
0fa3e1e64819283b8737fc4e5ab759f0cb4ac1a996e8a51cc4aa8025a457208e android.hardware.camera.device@3.2::ICameraDeviceSession
030be3d2b159cbde7920485807140f6b6064ef4a5de4a40a6c4bc8d2c72f7cd3 android.hardware.camera.device@3.2::types
5ba7947cee515d7a2359bfcbfb9678c1c3a768c288471919ac095b96ae6f3d40 android.hardware.camera.metadata@3.2::types
//删除该行
-f7e299d85033ac52d1095a35784fcfeaff43603f58c751e4153c85bbade3b330 android.hardware.camera.provider@2.4::ICameraProvider
重新生成的CameraProvider接口如下:
struct ICameraProvider : public ::android::hidl::base::V1_0::IBase {
virtual bool isRemote() const override {
return false; }
...
using getCameraDeviceInterface_V3_x_cb = std::function<void(::android::hardware::camera::common::V1_0::Status status, const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device)>;
virtual ::android::hardware::Return<void> getCameraDeviceInterface_V3_x(const ::android::hardware::hidl_string& cameraDeviceName, getCameraDeviceInterface_V3_x_cb _hidl_cb) = 0;
//新添加的接口
virtual ::android::hardware::Return<uint32_t> registerMemory(const ::android::hardware::hidl_handle& descriptor, uint32_t bufferSize, uint32_t bufferCount) = 0;
....
还需要在实现了ICameraProvider抽象类的CameraProvider类中实现新定义的registerMemory方法
CameraProvider.h头文件中添加registerMemory的声明
//hardware\interfaces\camera\provider\2.4\default\CameraProvider.h
--- a/camera/provider/2.4/default/CameraProvider.h
+++ b/camera/provider/2.4/default/CameraProvider.h
@@ -68,7 +68,7 @@ struct CameraProvider : public ICameraProvider, public camera_module_callbacks_t
Return<void> getCameraDeviceInterface_V3_x(
const hidl_string& cameraDeviceName,
getCameraDeviceInterface_V3_x_cb _hidl_cb) override;
//新接口声明声明
+ Return<uint32_t> registerMemory(const hidl_handle& descriptor, uint32_t bufferSize, uint32_t bufferCount) override;
private:
Mutex mCbLock;
sp<ICameraProviderCallback> mCallbacks = nullptr;
CameraProvider.cpp中实现该registerMemory
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -24,6 +24,8 @@
#include <cutils/properties.h>
#include <string.h>
#include <utils/Trace.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
namespace android {
@@ -523,6 +525,60 @@ Return<void> CameraProvider::getCameraDeviceInterface_V3_x(
return Void();
}
// 添加局部dumpImage方法,检验数据是否传递正确
+void dumpImage(unsigned char* pData,
+ uint32_t frameid,uint32_t stride,uint32_t height,uint32_t bytePerPixe) {
+ ALOGE("%s,%d E .", __FUNCTION__,__LINE__);
+
+ char buf[255];
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf), "/data/misc/camera/frame_%dx%d_%d.raw",
+ stride,height,frameid);
+ ALOGE("%s,%d buf : %s", __FUNCTION__,__LINE__,buf);
+ int file_fd = open(buf, O_RDWR | O_CREAT, 0666);
+ uint32_t size = stride*height*bytePerPixe;
+ if (file_fd >= 0)
+ {
+ ssize_t written_Len = write(file_fd, pData, size);
+ ALOGE("%s,%d : written number of %zd bytes to file %s", __FUNCTION__,__LINE__,written_Len,buf);
+ close(file_fd);
+ }
+ else
+ {
+ ALOGE("%s,%d : failed to write data to %s", __FUNCTION__,__LINE__,buf);
+ }
+ ALOGE("%s,%d X .", __FUNCTION__,__LINE__);
+}
+
// registerMemory接口实现
+Return<uint32_t> CameraProvider::registerMemory(const hidl_handle& descriptor, uint32_t bufferSize, uint32_t bufferCount) {
+ ALOGE("%s:%d,%d,%d", __FUNCTION__,bufferSize,bufferCount,descriptor->data[0]);
+ if (descriptor->numFds != 1) {
+ ALOGE("%s: camera memory descriptor has numFds %d (expect 1)",
+ __FUNCTION__, descriptor->numFds);
+ return 0;
+ }
+ if (descriptor->data[0] < 0) {
+ ALOGE("%s: camera memory descriptor has FD %d (expect >= 0)",
+ __FUNCTION__, descriptor->data[0]);
+ return 0;
+ }
+
+ sp<android::MemoryHeapBase> mHeap;
+ //由hidl_handle descriptor转换生成MemoryHeapBase
+ //MemoryHeapBase是内名共享内存定义的方法,以后会单独研究下MemoryHeapBase MemoryBase
+ mHeap = new android::MemoryHeapBase(descriptor->data[0], bufferSize * bufferCount,0,0);
+ sp<MemoryBase> *mBuffers;
+ mBuffers = new sp<MemoryBase>[bufferCount];
+ for (uint_t i = 0; i < bufferCount; i++) {
+ mBuffers[i] = new MemoryBase(mHeap,i * bufferSize, bufferSize);
+ }
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mBuffers[0]->getMemory(&offset, &size);
+ void* heapBase = heap->base();
+ //dump传递进CameraProvider的数据,检查数据是否正确
+ dumpImage((unsigned char*)heapBase,1,bufferSize,bufferCount,1);
+ //将由descriptor转换生成的MemoryHeapBase对象的HeapID放回给client用户
+ return mHeap->getHeapID();
+};
+
然后修改下编译文件
//hardware\interfaces\camera\provider\2.4\default\Android.bp
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -23,7 +23,8 @@ cc_library_shared {
"[email protected]",
"liblog",
"libhardware",
- "libcamera_metadata"
+ "libcamera_metadata",
+ "libbinder"
],
static_libs: [
"[email protected]"
至此CameraProvider的修改完成。
接着介绍下新定义的registerMemory如何使用,即如何将一个带有用户数据的Ashmem传递给CameraProvider
本文在CameraService中使用该方法,当然也可以在任何可以获得CameraProvider服务代理的地方使用,如相机应用。
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -25,11 +25,20 @@
#include <hidl/ServiceManagement.h>
#include <functional>
#include <camera_metadata_hidden.h>
//添加必要的头文件
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <hidlmemory/mapping.h>
namespace android {
using namespace ::android::hardware::camera;
using namespace ::android::hardware::camera::common::V1_0;
+using ::android::hardware::camera::device::V1_0::MemoryId;
//将必要的名称空间添加到本类中
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;
namespace {
// Hardcoded name for the passthrough HAL implementation, since it can't be discovered via the
@@ -522,6 +531,35 @@ status_t CameraProviderManager::ProviderInfo::initialize() {
return mapToStatusT(status);
}
+ // Shared memory related members
+ size_t buf_size = 1024 * 1024;// 1m
+ uint_t num_bufs = 1;
+ hidl_memory mHidlHeap;
+ native_handle_t* mHidlHandle; // contains one shared memory FD
+ sp<IAllocator> ashmemAllocator;
+ sp<IMemory> mHidlHeapMemory; // munmap happens in ~IMemory()
+ void* mHidlHeapMemData;
+ //获取IAllocator服务代理,IAllocator需要以后研究下
+ ashmemAllocator = IAllocator::getService("ashmem");
+ const size_t pagesize = getpagesize();
+ //大小对其到pagesize的整数倍
+ size_t size = ((buf_size * num_bufs + pagesize-1) & ~(pagesize-1));
+ //分配匿名共享内存
+ ashmemAllocator->allocate(size,
+ [&](bool success, const hidl_memory& mem) {
+ mHidlHandle = native_handle_clone(mem.handle());
+ mHidlHeap = hidl_memory("ashmem", mHidlHandle, size);
+ ALOGI("allocate %d", success);
+ });
+ //将内存映射到当前进程,mapMemory需要以后研究下
+ mHidlHeapMemory = mapMemory(mHidlHeap);
+ mHidlHeapMemData = mHidlHeapMemory->getPointer();
+ uint8_t*temp = (uint8_t*)mHidlHeapMemData;
+ //测试内容,如果在CameraProvider dumpImage方法保存的数据全部是0xFE,说明功能实现成功
+ memset(temp,0xFE,size);
+ //将带有用户数据的内名共享内存注册给CameraProvider
+ uint32_t memid = mInterface->registerMemory(mHidlHandle, buf_size, num_bufs);
+ ALOGI("memid %d", memid);
+
+
sp<StatusListener> listener = mManager->getStatusListener();
for (auto& device : devices) {
std::string id;
修改下编译文件
//frameworks\av\services\camera\libcameraservice\Android.mk
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -99,9 +99,12 @@ LOCAL_SHARED_LIBRARIES:= \
android.hardware.camera.device@1.0 \
vendor.qti.hardware.camera.device@1.0 \
android.hardware.camera.device@3.2 \
- android.hardware.camera.device@3.3
+ android.hardware.camera.device@3.3 \
+ android.hidl.allocator@1.0 \
+ android.hidl.memory@1.0\
+ libhidlmemory \
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq android.hidl.allocator@1.0 android.hidl.memory@1.0 libhidlmemory
LOCAL_C_INCLUDES += \
system/media/private/camera/include \
重新编译,将生成的so push到手机中,重启手机,发现在/data/misc/camera
目录下生成了
frame_1048576x1_1.raw
文件
打开查看其内如如下:
从dump数据看,其内容和CameraService传递的值是相同的。功能基本实现3
验证不可行,原因请查看android framework CameraMetadata与HIDL CameraMetadata的区别及相互转换 ↩︎
编译时会检查下当前的Hash和hardware\interfaces\current.txt是否匹配
代码在system\tools\hidl\Coordinator.cpp Coordinator::enforceHashes(…)。 ↩︎查看log时,发现SELinux : avc: denied { find } for interface=android.hidl.memory::IMapper相关的Log,可能还需要修改SELinux 权限问题,我们的项目已经将SELinux关闭了,哈哈。还有现在只实现了注册方法,应该还需要反注册,之后再完善吧。 ↩︎