CameraAPI2はデータをCamera HALに転送します。カメラパラメータは主にcamera_metadataを介して実現されます。最近のプロジェクトでは、YUVデータをCamera HALに転送する必要があり、サイズは数メガバイトです。これを達成するために既存のcamera_metadataを使用することは困難です(後で調査する必要があります)。実現可能性1)。
この機能を実現し、CameraAPI2がCamera HALにデータを転送する機能をさらに向上させるために、この記事では、ICameraProvider.halインターフェイスを拡張して匿名の共有メモリ(Ashmem)をCameraProviderプロセスに渡すことにより、この機能を実装します。
主な実装は次のとおりです
。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を再コンパイルします(2をコンパイルするには、hardware \ interfaces \ current.txtを変更する必要がある場合があります)
--- 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 \
再コンパイルして、生成されたものを電話にプッシュし、電話を再起動して、ファイルが/data/misc/camera
ディレクトリに生成されていることを確認し
frame_1048576x1_1.raw
ます
内容を開いて次のように表示します。ダンプデータから、CameraServiceによって渡された内容と値は同じです。基本機能実現3
検証は実行できません。理由について、AndroidフレームワークCameraMetadataとHIDL CameraMetadataの違いと変換 を確認してください↩︎
コンパイル時に、現在のハッシュとhardware \ interfaces \ current.txtが一致するかどうかをチェックします
コードはsystem \ tools \ hidl \ Coordinator.cpp Coordinator :: enforceHashes(…)にあります。↩︎ログを見ると、SELinux:avc:denied {find} for interface = android.hidl.memory :: IMapper関連のログが見つかりました。また、SELinux権限の問題を修正する必要があるかもしれません。プロジェクトはSELinuxを閉じました。また、現在は登録方法のみが実装されており、反登録が必要です。↩︎