[TOC]

概述

集成步骤

将Flatbuffer集成到我们的项目中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (BUILD_FLAT_BUFFERS_LIB)
# 官网文档
# https://google.github.io/flatbuffers/flatbuffers_guide_building.html
set(FLAT_BUFFERS_NAME flatbuffers) # 设置FlatBuffers的名称
set(FLAT_BUFFERS_VERSION v22.10.26) # 设置FlatBuffers的版本号
set(FLAT_BUFFERS_BASE_DIR ${LIB_DIR}/${FLAT_BUFFERS_NAME}/${FLAT_BUFFERS_VERSION}) # 设置flatbuffers的根目录
# 如下表示使用FLAT_BUFFERS源码进行编译
# 保证FlatBuffers 和项目的其余部分之间使用相同的编译器和链接器设置,因此避免了与使用不兼容库(例如调试/发布)等相关的问题
if (BUILD_FLAT_BUFFERS_WITH_SOURCE)
set(FLAT_BUFFERS_SRC_DIR ${FLAT_BUFFERS_BASE_DIR}/src/${FLAT_BUFFERS_NAME}-${FLAT_BUFFERS_VERSION})
add_subdirectory(${FLAT_BUFFERS_SRC_DIR} ${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build EXCLUDE_FROM_ALL)
else ()
set(FLAT_BUFFERS_INCLUDE_DIR ${FLAT_BUFFERS_BASE_DIR}/include)
set(FLAT_BUFFERS_LIB_DIR ${QNN_BASE_DIR}/target/${TARGET_OS}-${TARGET_ARCH}-${CMAKE_BUILD_TYPE}) # 根据系统版本设置依赖库的目录
set(FLAT_BUFFERS_LINK_DIR ${FLAT_BUFFERS_LIB_DIR})
set(FLAT_BUFFERS_LIB QNN QNN_main)
include_directories(${FLAT_BUFFERS_INCLUDE_DIR})
link_directories(${FLAT_BUFFERS_LINK_DIR})
endif ()
message(STATUS "[Dependency] flatbuffers FLAT_BUFFERS_INCLUDE_DIR = ${FLAT_BUFFERS_INCLUDE_DIR}")
message(STATUS "[Dependency] flatbuffers FLAT_BUFFERS_LINK_DIR = ${FLAT_BUFFERS_LINK_DIR}")
message(STATUS "[Dependency] flatbuffers FLAT_BUFFERS_LIB = ${FLAT_BUFFERS_LIB}")
message(STATUS "[Dependency] flatbuffers FLAT_BUFFERS_SRC_DIR = ${FLAT_BUFFERS_SRC_DIR}")
endif ()

集成到我们的工程中

1
2
3
# 现在只需根据需要将 flatbuffers 链接到您已经声明的目标。
# 如果 CMake > 2.8.11,flatbuffers 目标会自动携带标题搜索路径。
target_link_libraries(own_project_target PRIVATE flatbuffers)

集成代码

编写FlatBuffers的scheme文件

我们来编写一个FaceIndo.fbs的scheme文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 打电话的状态
enum FaceCallStatus:byte { F_CALL_NONE = 0, F_CALL_CALLING}

enum FaceDangerousStatus:byte { F_DANGEROUS_NONE = 0, F_DANGEROUS_SMOKE,F_DANGEROUS_SILENCE,F_DANGEROUS_DRINK,
F_DANGEROUS_OPEN_MOUTH,F_COVER_MOUTH,F_FACE_MASK,F_COVER_NONE

struct VPoint3 {
x:float;
y:float;
z:float;
}

struct VAngle {
yaw:float;
pitch:float;
roll:float;
}

table FaceInfo {
name:string;
index:short;
headLocation:VPoint3;
headDeflection:VAngle;

faceCount:[ubyte] (deprecated);
faceFeature:[float];

stateCallSingle:bool = false;
stateDangerDriveSingle:FaceDangerousStatus = F_DANGEROUS_NONE;
eye3dLandmark28Left:[VPoint3];
eye3dLandmark28Right:[VPoint3];
}

root_type FaceInfo;

关于scheme文件的详细介绍:FlatBuffers的scheme文件解析

编译Schema文件:

到我们编写的scheme文件保存为FaceInfo.fbs文件夹下,执行:

1
2
flatc --cpp FaceInfo.fbs
flatc --java FaceInfo.fbs

实例程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//
// Created by Frewen.Wang on 2022/11/19.
//
#include "FaceInfo_generated.h"
#include "aura/baselib/utils/AuraLog.h"

using namespace aura::aura_vision;

const char *TAG = "demo_flatbuffers";

/**
* 参考文档:https://github.com/google/flatbuffers/blob/master/samples/sample_binary.cpp
* @param argc
* @param argv
* @return
*/
int main(int argc, const char *argv[]) {
// Build up a serialized buffer algorithmically:
flatbuffers::FlatBufferBuilder builder;
// 创建FaceInfo的String字段:name
auto name = builder.CreateString("MyFace");
// 创建FaceInfo的short字段:name
short index = 123;
// 创建FaceIndo的struct字段:headLocation
auto headLocation = VPoint3(1.0f, 2.0f, 3.0f);
auto headDeflection = VAngle(1.0f, 2.0f, 3.0f);
// 创建FaceInfo的Vector<float>字段:faceFeature
float face_feature[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto faceFeature = builder.CreateVector(face_feature, 10);

auto point1 = builder.CreateStruct(VPoint3(1.0f, 2.0f, 3.0f));
auto point2 = builder.CreateStruct(VPoint3(4.0f, 5.0f, 6.0f));
auto point3 = builder.CreateStruct(VPoint3(7.0f, 8.0f, 9.0f));
std::vector<flatbuffers::Offset<const VPoint3 *>> eye3dLandmark28LeftVector;
eye3dLandmark28LeftVector.push_back(point1);
eye3dLandmark28LeftVector.push_back(point2);
eye3dLandmark28LeftVector.push_back(point3);
auto eye3dLandmark28Lefts = builder.CreateVector(eye3dLandmark28LeftVector);
std::vector<flatbuffers::Offset<const VPoint3 *>> eye3dLandmark28RightVector;
eye3dLandmark28RightVector.push_back(point1);
eye3dLandmark28RightVector.push_back(point2);
eye3dLandmark28RightVector.push_back(point3);
auto eye3dLandmark28Rights = builder.CreateVector(eye3dLandmark28RightVector);

auto gestureName1 = builder.CreateString("gesture1");
short gestureIndex1 = 12345;
auto gestureName2 = builder.CreateString("gesture2");
short gestureIndex2 = 6789;
auto gesture1 = CreateGestureInfo(builder, gestureName1, gestureIndex1);
auto gesture2 = CreateGestureInfo(builder, gestureName2, gestureIndex2);

// Create a FlatBuffer's `vector` from the `std::vector`.
// 创建FaceInfo的Table型数组对象:gesture_info_list
std::vector<flatbuffers::Offset<GestureInfo>> gestureVector;
gestureVector.push_back(gesture1);
gestureVector.push_back(gesture2);
auto gestureList = builder.CreateVector(gestureVector);

// 开始序列化根节点对象
builder.Finish(faceInfo);
// 我们通过此方法就可以进行序列化对象数据,然我们就可以将*buffer存储到硬盘上
uint8_t *buffer = builder.GetBufferPointer();
ALOGD(TAG, "serialization object success");

// 我们现在有了一个可以存储在磁盘上或通过网络发送的 FlatBuffer。
// ** file/network code goes here :) **
// access builder.GetBufferPointer() for builder.GetSize() bytes

// 下面,我们立即访问序列化之后的buffer数据(就好像我们刚刚收到它一样)。
auto newFaceInfo = GetFaceInfo(buffer);
// Get and test some scalar types from the FlatBuffer.
assert(newFaceInfo->name()->str() == "MyFace");
ALOGD(TAG, "deserialization object name:%s", newFaceInfo->name()->str().c_str());
assert(newFaceInfo->index() == 123);

auto newHeadLocation = newFaceInfo->head_deflection();
assert(newHeadLocation);
assert(newHeadLocation->yaw() == 1.0);
assert(newHeadLocation->pitch() == 2.0);
assert(newHeadLocation->roll() == 3.0);

ALOGD(TAG, "deserialization object success");
}