1 /*
2 * thumbnails.cpp - A service to produce thumbnails for algorithms
3 *
4 * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19 #include "thumbnails.h"
20
21 #include <algorithm>
22 #include <fstream>
23 #include <iostream>
24 #include <mutex>
25 #include <unordered_map>
26 #include <vector>
27
28 #include "image_processor.h"
29 #include "xcore/base/xcam_buffer.h"
30 #include "xcore/base/xcam_log.h"
31 #include "xcore/drm_buffer.h"
32 #include "xcore/drm_device.h"
33 #include "xcore/video_buffer.h"
34
35 namespace RkCam {
36
37 using namespace XCam;
38 using namespace RkCam::thumbnails;
39
40 namespace thumbnails {
41 // clang-format off
42 // Any bits of this mask is '1' means
43 // the image stream has to be get from SP device
44 #define RKISP20_MIPITX_S_NODE_MASK \
45 RKAIQ_PIPELINE_NODE_FAKE_SHORT
46
47 #define RKISP20_MIPITX_M_NODE_MASK \
48 RKAIQ_PIPELINE_NODE_FAKE_MIDDLE
49
50 #define RKISP20_MIPITX_L_NODE_MASK \
51 RKAIQ_PIPELINE_NODE_FAKE_LONG
52
53 #define RKISP20_SP_RAW_NODE_MASK \
54 RKAIQ_PIPELINE_NODE_FAKE_SHORT | \
55 RKAIQ_PIPELINE_NODE_FAKE_MIDDLE | \
56 RKAIQ_PIPELINE_NODE_FAKE_LONG
57
58 #define RKISP20_SP_NODE_MASK \
59 RKISP20_SP_RAW_NODE_MASK | \
60 RKAIQ_PIPELINE_NODE_BLC | \
61 RKAIQ_PIPELINE_NODE_DPCC | \
62 RKAIQ_PIPELINE_NODE_HDRMERGE | \
63 RKAIQ_PIPELINE_NODE_RAWNR | \
64 RKAIQ_PIPELINE_NODE_LSC | \
65 RKAIQ_PIPELINE_NODE_HDRTMO | \
66 RKAIQ_PIPELINE_NODE_GIC | \
67 RKAIQ_PIPELINE_NODE_DEBAYER | \
68 RKAIQ_PIPELINE_NODE_CCM | \
69 RKAIQ_PIPELINE_NODE_GAMMA | \
70 RKAIQ_PIPELINE_NODE_WDR | \
71 RKAIQ_PIPELINE_NODE_DEHAZE | \
72 RKAIQ_PIPELINE_NODE_3DLUT | \
73 RKAIQ_PIPELINE_NODE_LDCH | \
74 RKAIQ_PIPELINE_NODE_CSM | \
75 RKAIQ_PIPELINE_NODE_CP | \
76 RKAIQ_PIPELINE_NODE_IE
77
78 #define RKISP20_TNR_NODE_MASK \
79 RKISP20_SP_NODE_MASK | \
80 RKAIQ_PIPELINE_NODE_TNR
81
82 #define RKISP20_NR_NODE_MASK \
83 RKISP20_TNR_NODE_MASK | \
84 RKAIQ_PIPELINE_NODE_UVNR | \
85 RKAIQ_PIPELINE_NODE_YNR | \
86 RKAIQ_PIPELINE_NODE_SHARP | \
87 RKAIQ_PIPELINE_NODE_ORB
88
89 #define RKISP20_FEC_NODE_MASK \
90 RKISP20_NR_NODE_MASK | \
91 RKAIQ_PIPELINE_NODE_FEC
92 // clang-format on
93
94 const std::map<rkaiq_stream_type_t, uint64_t> Isp20DevToMaskMap = {
95 {RKISP20_STREAM_MIPITX_S, RKISP20_MIPITX_S_NODE_MASK},
96 {RKISP20_STREAM_MIPITX_M, RKISP20_MIPITX_M_NODE_MASK},
97 {RKISP20_STREAM_MIPITX_L, RKISP20_MIPITX_L_NODE_MASK},
98 {RKISP20_STREAM_SP_RAW, RKISP20_SP_RAW_NODE_MASK},
99 {RKISP20_STREAM_SP, RKISP20_SP_NODE_MASK},
100 {RKISP20_STREAM_NR, RKISP20_NR_NODE_MASK},
101 {RKISP20_STREAM_FEC, RKISP20_FEC_NODE_MASK}};
102
103 const std::map<rkaiq_stream_type_t, uint64_t> Isp21DevToMaskMap = {
104 {RKISP20_STREAM_MIPITX_S, RKISP20_MIPITX_S_NODE_MASK},
105 {RKISP20_STREAM_MIPITX_M, RKISP20_MIPITX_M_NODE_MASK},
106 {RKISP20_STREAM_MIPITX_L, RKISP20_MIPITX_L_NODE_MASK},
107 {RKISP20_STREAM_SP_RAW, RKISP20_SP_RAW_NODE_MASK},
108 {RKISP20_STREAM_SP, RKISP20_SP_NODE_MASK}};
109
ConfigLess(const rkaiq_thumbnails_config_t & lhs,const rkaiq_thumbnails_config_t & rhs)110 bool ConfigLess(const rkaiq_thumbnails_config_t& lhs, const rkaiq_thumbnails_config_t& rhs) {
111 if (lhs.width_intfactor <= rhs.width_intfactor &&
112 lhs.height_intfactor <= rhs.height_intfactor) {
113 return true;
114 } else if (lhs.width_intfactor > rhs.width_intfactor &&
115 lhs.height_intfactor > rhs.height_intfactor) {
116 return false;
117 } else {
118 // Unsupported
119 XCAM_ASSERT(0);
120 return true;
121 }
122 }
123
ConfigEqual(const rkaiq_thumbnails_config_t & lhs,const rkaiq_thumbnails_config_t & rhs)124 bool ConfigEqual(const rkaiq_thumbnails_config_t& lhs, const rkaiq_thumbnails_config_t& rhs) {
125 return (lhs.width_intfactor == rhs.width_intfactor &&
126 lhs.height_intfactor == rhs.height_intfactor &&
127 !memcmp(lhs.format, rhs.format, sizeof(lhs.format)) &&
128 lhs.after_nodes == rhs.after_nodes);
129 }
130
131 struct RefCountedVideoBuffer {
132 RefCountedVideoBuffer() = delete;
133
RefCountedVideoBufferRkCam::thumbnails::RefCountedVideoBuffer134 explicit RefCountedVideoBuffer(XCamVideoBuffer* buffer, bool takeRef = true) {
135 XCAM_ASSERT(buffer != nullptr);
136 this->buffer = buffer;
137 this->buffer->ref(this->buffer);
138 auto cnt = this->buffer->unref(this->buffer);
139 if (takeRef) {
140 this->buffer->ref(this->buffer);
141 cnt++;
142 }
143 LOGV_ANALYZER("%p ref count %d", this->buffer, cnt);
144 }
145
RefCountedVideoBufferRkCam::thumbnails::RefCountedVideoBuffer146 RefCountedVideoBuffer(const RefCountedVideoBuffer& other) {
147 this->buffer = other.buffer;
148 this->buffer->ref(this->buffer);
149 }
150
operator =RkCam::thumbnails::RefCountedVideoBuffer151 RefCountedVideoBuffer& operator=(const RefCountedVideoBuffer& other) {
152 if (this->buffer != other.buffer) {
153 this->buffer->unref(this->buffer);
154 this->buffer = other.buffer;
155 this->buffer->ref(this->buffer);
156 }
157
158 return *this;
159 }
160
RefCountedVideoBufferRkCam::thumbnails::RefCountedVideoBuffer161 RefCountedVideoBuffer(RefCountedVideoBuffer&& other) {
162 this->buffer = other.buffer;
163 other.buffer = nullptr;
164 }
165
operator =RkCam::thumbnails::RefCountedVideoBuffer166 RefCountedVideoBuffer& operator=(RefCountedVideoBuffer&& other) {
167 if (this->buffer != other.buffer) {
168 this->buffer->unref(this->buffer);
169 this->buffer = other.buffer;
170 // this->buffer->ref(this->buffer);
171 // other.buffer->unref(other.buffer);
172 other.buffer = nullptr;
173 }
174
175 return *this;
176 }
177
~RefCountedVideoBufferRkCam::thumbnails::RefCountedVideoBuffer178 ~RefCountedVideoBuffer() {
179 auto cnt = this->buffer->unref(this->buffer);
180 LOGV_ANALYZER("%p unref count %d", this->buffer, cnt);
181 }
182
importBufferRkCam::thumbnails::RefCountedVideoBuffer183 void importBuffer(XCamVideoBuffer* buffer) {
184 if (this->buffer == buffer) {
185 return;
186 }
187 this->buffer->unref(this->buffer);
188 this->buffer = buffer;
189 this->buffer->ref(this->buffer);
190 }
191
exportBufferRkCam::thumbnails::RefCountedVideoBuffer192 XCamVideoBuffer* exportBuffer() {
193 this->buffer->ref(this->buffer);
194 return this->buffer;
195 }
196
operator <(const RefCountedVideoBuffer & lhs,const RefCountedVideoBuffer & rhs)197 friend bool operator<(const RefCountedVideoBuffer& lhs, const RefCountedVideoBuffer& rhs) {
198 return (lhs.buffer->info.width * lhs.buffer->info.height) <
199 (rhs.buffer->info.width * rhs.buffer->info.height);
200 }
201
operator >(const RefCountedVideoBuffer & lhs,const RefCountedVideoBuffer & rhs)202 friend bool operator>(const RefCountedVideoBuffer& lhs, const RefCountedVideoBuffer& rhs) {
203 return (lhs.buffer->info.width * lhs.buffer->info.height) >
204 (rhs.buffer->info.width * rhs.buffer->info.height);
205 }
206
operator <=(const RefCountedVideoBuffer & lhs,const RefCountedVideoBuffer & rhs)207 friend bool operator<=(const RefCountedVideoBuffer& lhs, const RefCountedVideoBuffer& rhs) {
208 return !(lhs > rhs);
209 }
210
operator >=(const RefCountedVideoBuffer & lhs,const RefCountedVideoBuffer & rhs)211 friend bool operator>=(const RefCountedVideoBuffer& lhs, const RefCountedVideoBuffer& rhs) {
212 return !(lhs < rhs);
213 }
214
operator !=(const RefCountedVideoBuffer & lhs,const RefCountedVideoBuffer & rhs)215 friend bool operator!=(const RefCountedVideoBuffer& lhs, const RefCountedVideoBuffer& rhs) {
216 return (lhs < rhs) || (lhs > rhs);
217 }
218
operator ==(const RefCountedVideoBuffer & lhs,const RefCountedVideoBuffer & rhs)219 friend bool operator==(const RefCountedVideoBuffer& lhs, const RefCountedVideoBuffer& rhs) {
220 return !(lhs < rhs) && !(lhs > rhs);
221 }
222
IsValidRkCam::thumbnails::RefCountedVideoBuffer223 static bool IsValid(XCamVideoBuffer* buffer) {
224 // TODO(Cody): buffer should support mem type
225 return buffer->get_fd(buffer) >= 0;
226 }
227
228 XCamVideoBuffer* buffer;
229 };
230
231 struct ScalerParam {
232 std::shared_ptr<RefCountedVideoBuffer> src;
233 std::pair<rkaiq_thumbnails_config_t, std::shared_ptr<RefCountedVideoBuffer>> thumbnail;
234 };
235
236 class ThumbnailsConfig {
237 public:
238 ThumbnailsConfig() = default;
239 ~ThumbnailsConfig() = default;
240 ThumbnailsConfig(const ThumbnailsConfig&) = delete;
241 ThumbnailsConfig& operator=(const ThumbnailsConfig&) = delete;
242
243 bool ParseRequests(const CalibDbV2_Thumbnails_Param_t* configs);
244 void DumpConfig(const rkaiq_thumbnails_config_t& config);
245 void DumpConfigs();
246 std::vector<rkaiq_stream_type_t> GetEnabledStream();
247 const std::vector<rkaiq_thumbnails_config_t> GetStreamConfig(
248 const rkaiq_stream_type_t type) const;
249
250 private:
251 rkaiq_stream_type_t PipeNodesToStreamType(const rkaiq_thumbnails_config_t& config);
252 void GetStreamNodeMask(const rkaiq_stream_type_t type, uint64_t& after_nodes);
253
254 std::unordered_map<int, std::vector<rkaiq_thumbnails_config_t>> stream_configs_;
255 };
256
257 class ThumbnailsBufferManager {
258 public:
259 ThumbnailsBufferManager(const std::shared_ptr<ThumbnailsConfig>& config);
260 ~ThumbnailsBufferManager() = default;
261
262 XCamReturn InitializeBufferPools(const rkaiq_stream_type_t& type,
263 const XCamVideoBufferInfo& fullImageInfo);
264 void ReleasePools();
265 XCamVideoBuffer* GetBufferByConfig(const rkaiq_stream_type_t type,
266 const rkaiq_thumbnails_config_t& config);
267
268 private:
269 std::mutex mutex_;
270 std::shared_ptr<ThumbnailsConfig> config_;
271 std::vector<std::pair<rkaiq_thumbnails_config_t, SmartPtr<XCam::BufferPool>>> pools_;
272 };
273
274 class ScalerTask final : public XCam::ServiceTask<ScalerParam> {
275 public:
276 ScalerTask() = delete;
277 explicit ScalerTask(std::unique_ptr<ImageProcessor> proc);
278 ~ScalerTask() = default;
279 ScalerTask(const ScalerTask&) = delete;
280 const ScalerTask& operator=(const ScalerTask&) = delete;
281
282 XCam::TaskResult operator()(XCam::ServiceParam<ScalerParam>& p);
283
284 private:
285 std::unique_ptr<ImageProcessor> proc_;
286 };
287
GetStreamNodeMask(const rkaiq_stream_type_t type,uint64_t & after_nodes)288 void ThumbnailsConfig::GetStreamNodeMask(const rkaiq_stream_type_t type, uint64_t& after_nodes) {
289 after_nodes = Isp20DevToMaskMap.at(type);
290 }
291
PipeNodesToStreamType(const rkaiq_thumbnails_config_t & config)292 rkaiq_stream_type_t ThumbnailsConfig::PipeNodesToStreamType(
293 const rkaiq_thumbnails_config_t& config) {
294 rkaiq_stream_type_t type = RKISP_STREAM_NONE;
295
296 for (auto it : Isp20DevToMaskMap) {
297 LOGD_ANALYZER("type %d, mask %" PRIx64 "", it.first, it.second);
298 }
299
300 for (auto it : Isp20DevToMaskMap) {
301 if ((config.after_nodes & it.second) &&
302 (config.before_node != (config.before_node & it.second))) {
303 type = it.first;
304 LOGI_ANALYZER("owner %d matched type %d, before %" PRIx64 " after %" PRIx64 "",
305 config.owner_cookies, type, config.before_node, config.after_nodes);
306 break;
307 } else {
308 continue;
309 }
310 }
311
312 return type;
313 }
314
ParseRequests(const CalibDbV2_Thumbnails_Param_t * db)315 bool ThumbnailsConfig::ParseRequests(const CalibDbV2_Thumbnails_Param_t* db) {
316 XCAM_ASSERT(db != nullptr);
317
318 LOGD_ANALYZER("Dump configs db: ");
319 for (uint32_t j = 0; j < db->thumbnail_configs_len; j++) {
320 auto config = db->thumbnail_configs[j];
321 DumpConfig(config);
322 }
323
324 for (uint32_t j = 0; j < db->thumbnail_configs_len; j++) {
325 auto config = db->thumbnail_configs[j];
326 auto type = PipeNodesToStreamType(config);
327 if (type == RKISP_STREAM_NONE) {
328 LOGD_ANALYZER("Cannot find suitable stream for %d nodes after %" PRIx64 " before %" PRIx64 "",
329 config.owner_cookies, config.after_nodes, config.before_node);
330 continue;
331 }
332 if (!stream_configs_.count(static_cast<int>(type))) {
333 stream_configs_.emplace(type, std::vector<rkaiq_thumbnails_config_t>());
334 }
335 config.stream_type = type;
336 GetStreamNodeMask(type, config.after_nodes);
337 stream_configs_.at(type).push_back(config);
338 }
339
340 for (auto& stream_config : stream_configs_) {
341 auto& configs = stream_config.second;
342 std::sort(configs.begin(), configs.end(), ConfigLess);
343 configs.erase(std::unique(configs.begin(), configs.end(), ConfigEqual), configs.end());
344 }
345
346 return true;
347 }
348
DumpConfig(const rkaiq_thumbnails_config_t & config)349 void ThumbnailsConfig::DumpConfig(const rkaiq_thumbnails_config_t& config) {
350 LOGD_ANALYZER("type: %u, before: %" PRIx64 ", after: %" PRIx64
351 ", format: %c%c%c%c, w: 1/%u, h: 1/%u, count: %d",
352 config.stream_type, config.before_node, config.after_nodes, config.format[0],
353 config.format[1], config.format[2], config.format[3], config.width_intfactor,
354 config.height_intfactor, config.buffer_count);
355 }
356
DumpConfigs()357 void ThumbnailsConfig::DumpConfigs() {
358 for (auto& stream_config : stream_configs_) {
359 LOGD_ANALYZER("Dump stream %d configs:", stream_config.first);
360 for (auto config : stream_config.second) {
361 LOGD_ANALYZER("type: %u, before: %" PRIx64 ", after: %" PRIx64
362 ", format: %c%c%c%c, w: 1/%u, h: 1/%u, count: %d",
363 config.stream_type, config.before_node, config.after_nodes,
364 config.format[0], config.format[1], config.format[2], config.format[3],
365 config.width_intfactor, config.height_intfactor, config.buffer_count);
366 }
367 }
368 }
369
GetEnabledStream()370 std::vector<rkaiq_stream_type_t> ThumbnailsConfig::GetEnabledStream() {
371 std::vector<rkaiq_stream_type_t> types;
372
373 for (auto stream_config : stream_configs_) {
374 types.push_back(static_cast<rkaiq_stream_type_t>(stream_config.first));
375 }
376
377 return types;
378 }
379
GetStreamConfig(const rkaiq_stream_type_t type) const380 const std::vector<rkaiq_thumbnails_config_t> ThumbnailsConfig::GetStreamConfig(
381 const rkaiq_stream_type_t type) const {
382 auto config_iter = stream_configs_.find(type);
383 if (config_iter != stream_configs_.end()) {
384 return config_iter->second;
385 } else {
386 return {};
387 }
388 }
389
ThumbnailsBufferManager(const std::shared_ptr<ThumbnailsConfig> & config)390 ThumbnailsBufferManager::ThumbnailsBufferManager(const std::shared_ptr<ThumbnailsConfig>& config)
391 : config_(config) {}
392
InitializeBufferPools(const rkaiq_stream_type_t & type,const XCamVideoBufferInfo & fullImageInfo)393 XCamReturn ThumbnailsBufferManager::InitializeBufferPools(
394 const rkaiq_stream_type_t& type, const XCamVideoBufferInfo& fullImageInfo) {
395 std::unique_lock<std::mutex> lock(mutex_);
396 #if HAS_LIBDRM
397 if (!DrmDevice::Available()) {
398 LOGE_ANALYZER("drm device is not available!");
399 return XCAM_RETURN_ERROR_FAILED;
400 }
401
402 auto dev = std::make_shared<DrmDevice>();
403 if (dev == nullptr) {
404 LOGE_ANALYZER("Failed get drm device");
405 return XCAM_RETURN_ERROR_MEM;
406 }
407
408 for (auto& config : config_->GetStreamConfig(type)) {
409 VideoBufferInfo info;
410 info.width = fullImageInfo.width / config.width_intfactor;
411 info.height = fullImageInfo.height / config.height_intfactor;
412 #if 0
413 info.width = XCAM_ALIGN_UP(info.width, 2);
414 info.height = XCAM_ALIGN_UP(info.height, 2);
415 info.aligned_width = XCAM_ALIGN_UP(info.width, 16);
416 info.aligned_height = XCAM_ALIGN_UP(info.height, 4);
417 #endif
418 info.format =
419 rk_fmt_fourcc(config.format[0], config.format[1], config.format[2], config.format[3]);
420 info.init(info.format, info.width, info.height, info.aligned_width, info.aligned_height);
421 LOGE_ANALYZER("Initialize thumb: wxh: %dx%d, %dx%d", info.width, info.height,
422 info.aligned_width, info.aligned_height);
423 auto pool = SmartPtr<DrmBufferPool>(new DrmBufferPool(dev));
424 pool->set_video_info(info);
425 pool->reserve(config.buffer_count);
426 pools_.push_back(std::make_pair(config, std::move(pool)));
427 }
428
429 return XCAM_RETURN_NO_ERROR;
430 #else
431 return XCAM_RETURN_ERROR_MEM;
432 #endif
433 }
434
ReleasePools()435 void ThumbnailsBufferManager::ReleasePools() {
436 std::unique_lock<std::mutex> lock(mutex_);
437 pools_.clear();
438 }
439
GetBufferByConfig(const rkaiq_stream_type_t type,const rkaiq_thumbnails_config_t & config)440 XCamVideoBuffer* ThumbnailsBufferManager::GetBufferByConfig(
441 const rkaiq_stream_type_t type, const rkaiq_thumbnails_config_t& config) {
442 std::unique_lock<std::mutex> lock(mutex_);
443 auto poolIt = std::find_if(
444 pools_.begin(), pools_.end(),
445 [&type, &config](const std::pair<rkaiq_thumbnails_config_t, SmartPtr<BufferPool>>& pool) {
446 return ((type == pool.first.stream_type) && ConfigEqual(config, pool.first));
447 });
448 if (poolIt != pools_.end()) {
449 auto& pool = poolIt->second;
450 LOGD_ANALYZER("thumbnail pool size %d", pool->get_free_buffer_size());
451 if (pool->has_free_buffers()) {
452 auto buffer = pool->get_buffer();
453 return convert_to_external_buffer(buffer);
454 }
455 }
456 LOGE_ANALYZER("thumbnail cannot find available buffer pool");
457 return nullptr;
458 }
459
460 template <typename To, typename From>
461 To convert(From&);
462
463 template <>
convert(std::shared_ptr<RefCountedVideoBuffer> & dma)464 img_buffer_t convert(std::shared_ptr<RefCountedVideoBuffer>& dma) {
465 auto& info = dma->buffer->info;
466 img_buffer_t buf = {
467 NULL, NULL,
468 dma->buffer->get_fd(dma->buffer),
469 (int)info.width,
470 (int)info.height,
471 (int)info.aligned_width,
472 (int)info.aligned_height,
473 static_cast<rk_aiq_format_t>(info.format)
474 };
475
476 return buf;
477 }
478
ScalerTask(std::unique_ptr<ImageProcessor> proc)479 ScalerTask::ScalerTask(std::unique_ptr<ImageProcessor> proc) : proc_(std::move(proc)) {}
480
operator ()(ServiceParam<ScalerParam> & p)481 TaskResult ScalerTask::operator()(ServiceParam<ScalerParam>& p) {
482 auto& full = p.payload->src;
483 auto& scaled = p.payload->thumbnail.second;
484 auto& config = p.payload->thumbnail.first;
485 img_buffer_t src = convert<img_buffer_t>(full);
486 img_buffer_t dst = convert<img_buffer_t>(scaled);
487 auto ret = proc_->resize(src, dst, 0, 0);
488 LOGD_ANALYZER("thumbnail processed id:%d type: %d 1/%dx1/%d %dx%d->%dx%d, result: %d",
489 p.unique_id, config.stream_type, config.width_intfactor, config.height_intfactor,
490 full->buffer->info.width, full->buffer->info.height, scaled->buffer->info.width,
491 scaled->buffer->info.height, ret);
492 return ret == XCAM_RETURN_NO_ERROR ? TaskResult::kSuccess : TaskResult::kFailed;
493 }
494
495 } // namespace thumbnails
496
ThumbnailsService()497 ThumbnailsService::ThumbnailsService() : config_(new ThumbnailsConfig()), stopped_(true) {}
498
499 ThumbnailsService::~ThumbnailsService() = default;
500
Prepare(const CalibDbV2_Thumbnails_Param_t * calib)501 XCamReturn ThumbnailsService::Prepare(const CalibDbV2_Thumbnails_Param_t* calib) {
502 config_->ParseRequests(calib);
503 config_->DumpConfigs();
504
505 auto types = config_->GetEnabledStream();
506 if (types.size() > 0) {
507 bufferManager_ =
508 std::unique_ptr<ThumbnailsBufferManager>(new ThumbnailsBufferManager(config_));
509 for (auto t : types) {
510 std::unique_ptr<ImageProcessor> proc(new ImageProcessor());
511 proc->set_operator("rga");
512 auto scaler = std::unique_ptr<ScalerService>(new ScalerService(
513 std::unique_ptr<ScalerTask>(new ScalerTask(std::move(proc))), false, 0));
514 scalers_[static_cast<int>(t)] = std::move(scaler);
515 LOGV_ANALYZER("Created scaler for type %d", t);
516 }
517 } else {
518 LOGW_ANALYZER("thumbnail disabled");
519 return XCAM_RETURN_BYPASS;
520 }
521
522 return XCAM_RETURN_NO_ERROR;
523 }
524
Start()525 XCamReturn ThumbnailsService::Start() {
526 // TODO(Cody): Add get full stream info from HWI
527 // Use buffer manager to initialize buffer pool
528 if (!stopped_) {
529 LOGW_ANALYZER("thumbnail already started");
530 return XCAM_RETURN_ERROR_PARAM;
531 }
532 for (auto t : config_->GetEnabledStream()) {
533 XCamVideoBufferInfo fullImageInfo = {
534 RK_PIX_FMT_NV12, 16, 2688, 1520, 2688, 1520, XCAM_ALIGN_UP(int(2688*1520*3/2), 8), 2, {0}, {0}};
535 bufferManager_->InitializeBufferPools(t, fullImageInfo);
536 LOGD_ANALYZER("Initialize buffer for type %d", t);
537 }
538
539 for (auto& scaler : scalers_) {
540 scaler.second->start();
541 }
542
543 stopped_ = false;
544 LOGV_ANALYZER("thumbnail started");
545
546 return XCAM_RETURN_NO_ERROR;
547 }
548
Stop()549 XCamReturn ThumbnailsService::Stop() {
550 if (stopped_) {
551 LOGW_ANALYZER("thumbnail stopped");
552 return XCAM_RETURN_ERROR_PARAM;
553 }
554
555 stopped_ = true;
556
557 for (auto& scaler : scalers_) {
558 scaler.second->stop();
559 }
560
561 bufferManager_->ReleasePools();
562
563 LOGV_ANALYZER("thumbnail stopped");
564 return XCAM_RETURN_NO_ERROR;
565 }
566
SetResultCallback(const ResultCallback & cb)567 void ThumbnailsService::SetResultCallback(const ResultCallback& cb) { callback_ = cb; }
568
OnFrameEvent(const rkaiq_image_source_t & source)569 void ThumbnailsService::OnFrameEvent(const rkaiq_image_source_t& source) {
570 if (stopped_ || !scalers_.count(source.src_type)) {
571 LOGE_ANALYZER("Unsuported image source type %d or stopped", source.src_type);
572 return;
573 }
574
575 #if 1
576 if (source.frame_id == 1) {
577 std::string path = "/data/source_";
578 path.append(std::to_string(source.frame_id));
579 path.append("_");
580 path.append(std::to_string(source.image_source->info.width));
581 path.append(std::to_string(source.image_source->info.height));
582 path.append(".yuv");
583 std::ofstream ofs(path, std::ios::binary);
584 char* ptr = reinterpret_cast<char*>(source.image_source->map(source.image_source));
585 size_t size = source.image_source->info.size;
586 ofs.write(ptr, size);
587 }
588 #endif
589
590 if (RefCountedVideoBuffer::IsValid(source.image_source)) {
591 LOGD_ANALYZER(">>>>>> source type %d , w %d h %d", source.src_type, source.image_source->info.width,
592 source.image_source->info.height);
593 auto src = std::make_shared<RefCountedVideoBuffer>(source.image_source);
594 auto& scaler = scalers_.at(source.src_type);
595 auto& configs = config_->GetStreamConfig(source.src_type);
596 for (auto& config : configs) {
597 auto* buf = bufferManager_->GetBufferByConfig(source.src_type, config);
598 if (buf) {
599 auto dst = std::make_shared<RefCountedVideoBuffer>(buf, false);
600 if (*(src) <= *(dst)) {
601 LOGW_ANALYZER("thumbnail src %dx%d is smaller than or equal to dst %dx%d",
602 src->buffer->info.width, src->buffer->info.height, dst->buffer->info.width,
603 dst->buffer->info.height);
604 continue;
605 }
606 ServiceParam<ScalerParam> param;
607 param.state = XCam::ParamState::kAllocated;
608 param.unique_id = source.frame_id;
609 param.payload = std::make_shared<ScalerParam>();
610 param.payload->src = src;
611 src = dst;
612 param.payload->thumbnail = std::make_pair(config, dst);
613 scaler->enqueue(param);
614 LOGI_ANALYZER("thumbnail enqueue id %d type %d 1/%d x 1/%d to scaler",
615 source.frame_id, source.src_type, config.width_intfactor,
616 config.height_intfactor);
617 } else {
618 LOGE_ANALYZER("Cannot get buffer for config : ");
619 config_->DumpConfig(config);
620 }
621 }
622 }
623
624 for (auto& s : scalers_) {
625 while (true) {
626 auto p = s.second->dequeue();
627 if (p.state == ParamState::kProcessedSuccess) {
628 auto& config = p.payload->thumbnail.first;
629 auto& buf = p.payload->thumbnail.second;
630 LOGD_ANALYZER("thumbnail dequeue id %d type %d 1/%d x 1/%d from scaler",
631 p.unique_id, config.stream_type, config.width_intfactor,
632 config.height_intfactor);
633 rkaiq_thumbnails_t result;
634 result.config = config;
635 result.frame_id = p.unique_id;
636 result.buffer = buf->exportBuffer();
637 callback_(result);
638 result.buffer->unref(result.buffer);
639 } else {
640 break;
641 }
642 }
643 }
644 }
645
646 } // namespace RkCam
647