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關閉了,哈哈。還有現在只實現了註冊方法,應該還需要反註冊,之後再完善吧。 ↩︎