SSCMA-Micro CPP SDK  v2.0.0
SSCMA-Micro is a cross-platform machine learning inference framework designed for embedded devices.
sample.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <memory>
4 #include <string>
5 #include <vector>
6 
7 #include "core/ma_core.h"
8 #include "core/utils/ma_base64.h"
9 #include "porting/ma_porting.h"
10 #include "resource.hpp"
12 
13 namespace ma::server::callback {
14 
15 using namespace ma;
16 
17 class Sample final : public std::enable_shared_from_this<Sample> {
18 public:
19  std::shared_ptr<Sample> getptr() {
20  return shared_from_this();
21  }
22 
23  [[nodiscard]] static std::shared_ptr<Sample> create(const std::vector<std::string>& args, Transport& transport, Encoder& encoder, size_t task_id) {
24  return std::shared_ptr<Sample>{new Sample{args, transport, encoder, task_id}};
25  }
26 
27  ~Sample() {
28  static_resource->is_sample = false;
29  }
30 
31  inline void run() {
32  prepare();
33  }
34 
35 protected:
36  Sample(const std::vector<std::string>& args, Transport& transport, Encoder& encoder, size_t task_id) {
37  MA_ASSERT(args.size() >= 2);
38  _cmd = args[0];
39  _n_times = std::atoi(args[1].c_str());
40 
41  _ret = MA_OK;
42 
43  _sensor = nullptr;
44  _transport = &transport;
45  _encoder = &encoder;
46 
47  _times = 0;
48 
49  _task_id = task_id;
50 
51 #if MA_SENSOR_ENCODE_USE_STATIC_BUFFER
52  _buffer = reinterpret_cast<void*>(MA_SENSOR_ENCODE_STATIC_BUFFER_ADDR);
53  _buffer_size = 0;
54 #endif
55 
56  static_resource->is_sample = true;
57  }
58 
59 private:
60  void prepare() {
61  if (!prepareSensor()) [[unlikely]]
62  goto Err;
63 
64  switch (_sensor->getType()) {
66  directReply();
67  return static_resource->executor->submit([_this = std::move(getptr())](const std::atomic<bool>&) { _this->eventLoopCamera(); });
68  default:
69  _ret = MA_ENOTSUP;
70  directReply();
71  }
72 
73 Err:
74  directReply();
75  }
76 
77  bool prepareSensor() {
78  const auto& sensors = static_resource->device->getSensors();
79  auto it = std::find_if(sensors.begin(), sensors.end(), [&](const Sensor* s) { return s->getID() == static_resource->current_sensor_id; });
80  if (it == sensors.end()) {
81  return false;
82  }
83  _sensor = *it;
84  auto* camera = static_cast<Camera*>(_sensor);
85  _ret = camera->startStream(Camera::StreamMode::kRefreshOnReturn);
86  return isEverythingOk();
87  }
88 
89  void directReply() {
90  _encoder->begin(MA_MSG_TYPE_RESP, _ret, _cmd);
91  _encoder->write(_sensor, _sensor->currentPresetIdx());
92  _encoder->end();
93  _transport->send(reinterpret_cast<const char*>(_encoder->data()), _encoder->size());
94  }
95 
96  void eventReply() {
97  _encoder->begin(MA_MSG_TYPE_EVT, _ret, _cmd);
98  _encoder->write("count", _times);
99 #if MA_SENSOR_ENCODE_USE_STATIC_BUFFER
100  reinterpret_cast<char*>(_buffer)[_buffer_size] = '\0';
101  _encoder->write("image", reinterpret_cast<char*>(_buffer), _buffer_size);
102 #else
103  _encoder->write("image", _buffer);
104 #endif
105  if (_event_hook)
106  _event_hook(*_encoder);
107  _encoder->end();
108  _transport->send(reinterpret_cast<const char*>(_encoder->data()), _encoder->size());
109  }
110 
111  void eventLoopCamera() {
112  if ((_n_times >= 0) & (_times++ >= _n_times)) [[unlikely]]
113  return;
114  if (static_resource->current_task_id.load() != _task_id) [[unlikely]]
115  return;
116 
117  auto camera = static_cast<Camera*>(_sensor);
118  auto frame = ma_img_t{};
119  int buffer_size = 0;
120 
121  _ret = camera->retrieveFrame(frame, MA_PIXEL_FORMAT_JPEG);
122  if (!isEverythingOk()) [[unlikely]]
123  goto Err;
124 
125  buffer_size = 4 * ((frame.size + 2) / 3);
126 #if MA_SENSOR_ENCODE_USE_STATIC_BUFFER
127  if (buffer_size > MA_SENSOR_ENCODE_STATIC_BUFFER_SIZE) {
128  MA_LOGE(MA_TAG, "buffer_size > MA_SENSOR_ENCODE_STATIC_BUFFER_SIZE");
129  goto Err;
130  }
131  _buffer_size = buffer_size;
132 #else
133  if (buffer_size > _buffer.size()) {
134  _buffer.resize(buffer_size + 1);
135  }
136 #endif
137 
138  {
139  auto ret = ma::utils::base64_encode(reinterpret_cast<unsigned char*>(frame.data),
140  frame.size,
141 #if MA_SENSOR_ENCODE_USE_STATIC_BUFFER
142  reinterpret_cast<char*>(_buffer),
143 #else
144  reinterpret_cast<char*>(_buffer.data()),
145 #endif
146  &buffer_size);
147 #if MA_SENSOR_ENCODE_USE_STATIC_BUFFER
148  static_cast<char*>(_buffer)[buffer_size] = '\0';
149 #else
150  _buffer[buffer_size] = '\0';
151 #endif
152  if (ret != MA_OK) {
153  MA_LOGE(MA_TAG, "base64_encode failed: %d", ret);
154  }
155  }
156 
157  camera->returnFrame(frame);
158 
159  if (!_event_hook) {
160  _event_hook = [&frame](Encoder& encoder) {
161  int16_t rotation = static_cast<int>(frame.rotate) * 90;
162  encoder.write("rotation", rotation);
163  encoder.write("width", frame.width);
164  encoder.write("height", frame.height);
165  };
166  }
167 
168  eventReply();
169 
170  static_resource->executor->submit([_this = std::move(getptr())](const std::atomic<bool>&) { _this->eventLoopCamera(); });
171  return;
172 
173 Err:
174  eventReply();
175  }
176 
177  inline bool isEverythingOk() const {
178  return _ret == MA_OK;
179  }
180 
181 private:
182  std::string _cmd;
183  int32_t _n_times;
184 
185  ma_err_t _ret;
186 
187  Sensor* _sensor;
188  Transport* _transport;
189  Encoder* _encoder;
190 
191  size_t _task_id;
192  int32_t _times;
193 
194  std::function<void(Encoder&)> _event_hook;
195 
196 #if MA_SENSOR_ENCODE_USE_STATIC_BUFFER
197 #ifndef MA_SENSOR_ENCODE_STATIC_BUFFER_ADDR
198 #error "MA_SENSOR_ENCODE_STATIC_BUFFER_ADDR is not defined"
199 #endif
200 #ifndef MA_SENSOR_ENCODE_STATIC_BUFFER_SIZE
201 #error "MA_SENSOR_ENCODE_STATIC_BUFFER_SIZE is not defined"
202 #endif
203  void* _buffer;
204  size_t _buffer_size;
205 #else
206  std::string _buffer;
207 #endif
208 };
209 
210 } // namespace ma::server::callback
Definition: ma_camera.h:13
virtual ma_err_t startStream(StreamMode mode) noexcept=0
Definition: ma_codec_base.h:14
Definition: ma_sensor.h:12
Definition: ma_transport.h:12
Definition: sample.hpp:17
~Sample()
Definition: sample.hpp:27
Sample(const std::vector< std::string > &args, Transport &transport, Encoder &encoder, size_t task_id)
Definition: sample.hpp:36
void run()
Definition: sample.hpp:31
static std::shared_ptr< Sample > create(const std::vector< std::string > &args, Transport &transport, Encoder &encoder, size_t task_id)
Definition: sample.hpp:23
std::shared_ptr< Sample > getptr()
Definition: sample.hpp:19
#define MA_LOGE(TAG,...)
Definition: ma_debug.h:30
#define MA_ASSERT(expr)
Definition: ma_debug.h:119
#define MA_TAG
Definition: ma_debug.h:9
@ MA_MSG_TYPE_RESP
Definition: ma_types.h:252
@ MA_MSG_TYPE_EVT
Definition: ma_types.h:252
ma_err_t
Definition: ma_types.h:21
@ MA_ENOTSUP
Definition: ma_types.h:31
@ MA_OK
Definition: ma_types.h:23
@ MA_PIXEL_FORMAT_JPEG
Definition: ma_types.h:109
Definition: algorithm.hpp:11
ma_err_t base64_encode(const unsigned char *in, int in_len, char *out, int *out_len)
Definition: ma_base64.cpp:41
Definition: ma_cv.cpp:7
#define static_resource
Definition: resource.hpp:64
Definition: ma_types.h:124