xref: /OK3568_Linux_fs/external/camera_engine_rkaiq/rkaiq/aiq_core/thumbnails.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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