1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "image_effect_filter.h"
17 
18 #include "common_utils.h"
19 #include "delegate.h"
20 #include "effect_log.h"
21 #include "efilter.h"
22 #include "efilter_factory.h"
23 #include "native_effect_base.h"
24 #include "native_common_utils.h"
25 #include "memcpy_helper.h"
26 #include "format_helper.h"
27 #include "event_report.h"
28 #include <cstring>
29 
30 using namespace OHOS::Media;
31 using namespace OHOS::Media::Effect;
32 
33 namespace {
34     constexpr char const *PARA_SRC_EFFECT_BUFFER = "PARA_SRC_EFFECT_BUFFER";
35     constexpr char const *PARA_RENDER_WITH_SRC_AND_DST = "PARA_RENDER_WITH_SRC_AND_DST";
36     constexpr char const *PARA_RENDER_INFO = "PARA_RENDER_INFO";
37 
38     constexpr int const MAX_CHAR_LEN = 1024;
39 
40     std::mutex filterMutex_;
41 }
42 
43 static std::vector<std::shared_ptr<ImageEffect_FilterNames>> sOHFilterNames;
44 
SetParameter(const std::string & key,Plugin::Any & param)45 void OH_EffectFilter::SetParameter(const std::string &key, Plugin::Any &param)
46 {
47     params_.erase(key);
48     params_.emplace(key, param);
49 }
50 
GetParameter(const std::string & key,Plugin::Any & param)51 ErrorCode OH_EffectFilter::GetParameter(const std::string &key, Plugin::Any &param)
52 {
53     auto it = params_.find(key);
54     if (it == params_.end()) {
55         return ErrorCode::ERR_NO_VALUE;
56     }
57 
58     param = std::move(it->second);
59     return ErrorCode::SUCCESS;
60 }
61 
RemoveParameter(const std::string & key)62 void OH_EffectFilter::RemoveParameter(const std::string &key)
63 {
64     params_.erase(key);
65 }
66 
67 class FilterDelegate : public IFilterDelegate {
68 public:
FilterDelegate(const OH_EffectFilterInfo * info,const ImageEffect_FilterDelegate * delegate)69     FilterDelegate(const OH_EffectFilterInfo *info, const ImageEffect_FilterDelegate *delegate)
70         : ohInfo_(*info), ohDelegate_(delegate) {}
71 
72     ~FilterDelegate() override = default;
73 
Render(void * efilter,EffectBuffer * src,EffectBuffer * dst,std::shared_ptr<EffectContext> & context)74     bool Render(void *efilter, EffectBuffer *src, EffectBuffer *dst, std::shared_ptr<EffectContext> &context) override
75     {
76         EFFECT_LOGI("FilterDelegate Render with src and dst.");
77         OH_EffectFilter *ohEFilter = (OH_EffectFilter *)efilter;
78         CHECK_AND_RETURN_RET_LOG(ohEFilter != nullptr && ohEFilter->filter_ != nullptr, false,
79             "FilterDelegateRender: filter is null!");
80         Plugin::Any param = true;
81         ohEFilter->SetParameter(PARA_RENDER_WITH_SRC_AND_DST, param);
82         Plugin::Any any = context;
83         ohEFilter->SetParameter(PARA_RENDER_INFO, any);
84 
85         MemcpyHelper::CopyData(src, dst);
86         bool res = Render(efilter, dst, context);
87         ohEFilter->RemoveParameter(PARA_RENDER_WITH_SRC_AND_DST);
88         ohEFilter->RemoveParameter(PARA_RENDER_INFO);
89         return res;
90     }
91 
Render(void * efilter,EffectBuffer * src,std::shared_ptr<EffectContext> & context)92     bool Render(void *efilter, EffectBuffer *src, std::shared_ptr<EffectContext> &context) override
93     {
94         EFFECT_LOGI("FilterDelegate Render.");
95         std::unique_ptr<OH_EffectBufferInfo> srcBuffer = std::make_unique<OH_EffectBufferInfo>();
96         srcBuffer->addr = src->buffer_;
97         srcBuffer->width = static_cast<int32_t>(src->bufferInfo_->width_);
98         srcBuffer->height = static_cast<int32_t>(src->bufferInfo_->height_);
99         srcBuffer->rowSize = static_cast<int32_t>(src->bufferInfo_->rowStride_);
100         NativeCommonUtils::SwitchToOHFormatType(src->bufferInfo_->formatType_, srcBuffer->format);
101         srcBuffer->timestamp = src->extraInfo_->timestamp;
102 
103         OH_EffectFilter *ohEFilter = static_cast<OH_EffectFilter *>(efilter);
104         CHECK_AND_RETURN_RET_LOG(ohEFilter != nullptr && ohEFilter->filter_ != nullptr, false,
105             "FilterDelegateRender: filter is null!");
106 
107         Plugin::Any any = src;
108         ohEFilter->SetParameter(PARA_SRC_EFFECT_BUFFER, any);
109         Plugin::Any parameter = context;
110         ohEFilter->SetParameter(PARA_RENDER_INFO, parameter);
111 
112         OH_EffectFilterDelegate_PushData pushData = [](OH_EffectFilter *filter, OH_EffectBufferInfo *dst) {
113             FilterDelegate::PushData(filter, dst);
114         };
115 
116         bool res = ohDelegate_->render((OH_EffectFilter *)efilter, srcBuffer.get(), pushData);
117         ohEFilter->RemoveParameter(PARA_SRC_EFFECT_BUFFER);
118         ohEFilter->RemoveParameter(PARA_RENDER_INFO);
119         return res;
120     }
121 
SetValue(void * efilter,const std::string & key,const Plugin::Any & value)122     bool SetValue(void *efilter, const std::string &key, const Plugin::Any &value) override
123     {
124         EFFECT_LOGD("FilterDelegate SetValue.");
125         std::unique_ptr<ImageEffect_Any> ohValue = std::make_unique<ImageEffect_Any>();
126         NativeCommonUtils::SwitchToOHAny(value, ohValue.get());
127         return ohDelegate_->setValue((OH_EffectFilter *)efilter, key.c_str(), ohValue.get());
128     }
129 
Save(void * efilter,EffectJsonPtr & res)130     bool Save(void *efilter, EffectJsonPtr &res) override
131     {
132         EFFECT_LOGI("FilterDelegate Save.");
133         char *result = nullptr;
134         if (!ohDelegate_->save((OH_EffectFilter *)efilter, &result)) {
135             return false;
136         }
137         if (result == nullptr) {
138             return true;
139         }
140         std::string content = result;
141         res = JsonHelper::ParseJsonData(content);
142         return true;
143     }
144 
Restore(const EffectJsonPtr & values)145     void *Restore(const EffectJsonPtr &values) override
146     {
147         EFFECT_LOGI("FilterDelegate Restore.");
148         std::string valueStr = values->ToString();
149         return ohDelegate_->restore(valueStr.c_str());
150     }
151 
GetEffectInfo()152     void *GetEffectInfo() override
153     {
154         EFFECT_LOGI("FilterDelegate GetEffectInfo.");
155         return &ohInfo_;
156     }
157 protected:
PushData(OH_EffectFilter * filter,OH_EffectBufferInfo * dst)158     static void PushData(OH_EffectFilter *filter, OH_EffectBufferInfo *dst)
159     {
160         CHECK_AND_RETURN_LOG(dst != nullptr && filter != nullptr && filter->filter_ != nullptr,
161             "FilterDelegatePushData: filter is null!");
162         Plugin::Any param;
163         if (filter->GetParameter(PARA_RENDER_WITH_SRC_AND_DST, param) == ErrorCode::SUCCESS) {
164             return;
165         }
166 
167         Plugin::Any value;
168         ErrorCode res = filter->GetParameter(PARA_SRC_EFFECT_BUFFER, value);
169         CHECK_AND_RETURN_LOG(res == ErrorCode::SUCCESS, "FilterDelegatePushData: get param fail! key=%{public}s",
170             PARA_SRC_EFFECT_BUFFER);
171 
172         EffectBuffer *src = nullptr;
173         res = CommonUtils::ParseAny(value, src);
174         CHECK_AND_RETURN_LOG(res == ErrorCode::SUCCESS && src != nullptr,
175             "FilterDelegatePushData: parse EffectBuffer ptr fail! res=%{public}d", res);
176 
177         CHECK_AND_RETURN_LOG(src->buffer_ != nullptr, "FilterDelegatePushData: buffer of src is null!");
178 
179         CHECK_AND_RETURN_LOG(src->bufferInfo_ != nullptr && src->extraInfo_ != nullptr,
180             "FilterDelegatePushData: bufferInfo of src is null or extraInfo of src is null!");
181 
182         if (dst->addr == src->buffer_) {
183             std::shared_ptr<EffectBuffer> effectBuffer = std::make_shared<EffectBuffer>(src->bufferInfo_,
184                 dst->addr, src->extraInfo_);
185             Plugin::Any any;
186             res = filter->GetParameter(PARA_RENDER_INFO, any);
187             CHECK_AND_RETURN_LOG(res == ErrorCode::SUCCESS, "FilterDelegatePushData: get param fail! key=%{public}s",
188                                  PARA_RENDER_INFO);
189 
190             auto &context = Plugin::AnyCast<std::shared_ptr<EffectContext> &>(any);
191             EFFECT_LOGE("OH_EffectFilter PushData bufferType %{public}d", effectBuffer->extraInfo_->bufferType);
192             filter->filter_->PushData(effectBuffer.get(), context);
193             return;
194         }
195 
196         std::shared_ptr<BufferInfo> bufferInfo = std::make_unique<BufferInfo>();
197         bufferInfo->width_ = static_cast<uint32_t>(dst->width);
198         bufferInfo->height_ = static_cast<uint32_t>(dst->height);
199         bufferInfo->rowStride_ = static_cast<uint32_t>(dst->rowSize);
200         NativeCommonUtils::SwitchToFormatType(dst->format, bufferInfo->formatType_);
201         bufferInfo->len_ =
202             FormatHelper::CalculateDataRowCount(bufferInfo->height_, bufferInfo->formatType_) * bufferInfo->rowStride_;
203         std::shared_ptr<ExtraInfo> extraInfo = std::make_unique<ExtraInfo>();
204         *extraInfo = *src->extraInfo_;
205         extraInfo->bufferType = BufferType::DEFAULT;
206         extraInfo->surfaceBuffer = nullptr;
207         std::shared_ptr<EffectBuffer> effectBuffer = std::make_shared<EffectBuffer>(bufferInfo, dst->addr, extraInfo);
208 
209         Plugin::Any any;
210         res = filter->GetParameter(PARA_RENDER_INFO, any);
211         CHECK_AND_RETURN_LOG(res == ErrorCode::SUCCESS, "FilterDelegatePushData: get param fail! key=%{public}s",
212             PARA_RENDER_INFO);
213 
214         auto &context = Plugin::AnyCast<std::shared_ptr<EffectContext> &>(any);
215         filter->filter_->PushData(effectBuffer.get(), context);
216     }
217 private:
218     OH_EffectFilterInfo ohInfo_;
219     const ImageEffect_FilterDelegate *ohDelegate_;
220 };
221 
~OH_EffectFilterInfo()222 OH_EffectFilterInfo::~OH_EffectFilterInfo()
223 {
224     if (effectBufferType != nullptr) {
225         delete[] effectBufferType;
226         effectBufferType = nullptr;
227     }
228     if (effectFormat != nullptr) {
229         delete[] effectFormat;
230         effectFormat = nullptr;
231     }
232 }
233 
234 #ifdef __cplusplus
235 extern "C" {
236 #endif
237 
238 EFFECT_EXPORT
OH_EffectFilterInfo_Create()239 OH_EffectFilterInfo *OH_EffectFilterInfo_Create()
240 {
241     std::unique_ptr<OH_EffectFilterInfo> info = std::make_unique<OH_EffectFilterInfo>();
242     return info.release();
243 }
244 
245 EFFECT_EXPORT
OH_EffectFilterInfo_SetFilterName(OH_EffectFilterInfo * info,const char * name)246 ImageEffect_ErrorCode OH_EffectFilterInfo_SetFilterName(OH_EffectFilterInfo *info, const char *name)
247 {
248     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
249         "InfoSetFilterName: input parameter info is null!");
250     CHECK_AND_RETURN_RET_LOG(name != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
251         "InfoSetFilterName: input parameter name is null!");
252     CHECK_AND_RETURN_RET_LOG(strlen(name) < MAX_CHAR_LEN, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
253         "InfoSetFilterName: the length of input parameter name is too long! len = %{public}zu", strlen(name));
254     EFFECT_LOGD("Set filter name. name=%{public}s", name);
255     info->filterName = name;
256     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
257 }
258 
259 EFFECT_EXPORT
OH_EffectFilterInfo_GetFilterName(OH_EffectFilterInfo * info,char ** name)260 ImageEffect_ErrorCode OH_EffectFilterInfo_GetFilterName(OH_EffectFilterInfo *info, char **name)
261 {
262     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
263         "InfoGetFilterName: input parameter info is null!");
264     CHECK_AND_RETURN_RET_LOG(name != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
265         "InfoGetFilterName: input parameter name is null!");
266 
267     *name = const_cast<char *>(info->filterName.c_str());
268     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
269 }
270 
271 EFFECT_EXPORT
OH_EffectFilterInfo_SetSupportedBufferTypes(OH_EffectFilterInfo * info,uint32_t size,ImageEffect_BufferType * bufferTypeArray)272 ImageEffect_ErrorCode OH_EffectFilterInfo_SetSupportedBufferTypes(OH_EffectFilterInfo *info, uint32_t size,
273     ImageEffect_BufferType *bufferTypeArray)
274 {
275     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
276         "InfoSetSupportedBufferTypes: input parameter info is null!");
277     CHECK_AND_RETURN_RET_LOG(size > 0, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
278         "InfoSetSupportedBufferTypes: input parameter size is invalid! size=%{public}d", size);
279     CHECK_AND_RETURN_RET_LOG(bufferTypeArray != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
280         "InfoSetSupportedBufferTypes: input parameter bufferTypeArray is null!");
281     EFFECT_LOGD("Set supported buffer types. size=%{public}d", size);
282     info->supportedBufferTypes.clear();
283     for (uint32_t index = 0; index < size; index++) {
284         info->supportedBufferTypes.emplace(bufferTypeArray[index]);
285     }
286     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
287 }
288 
289 EFFECT_EXPORT
OH_EffectFilterInfo_GetSupportedBufferTypes(OH_EffectFilterInfo * info,uint32_t * size,ImageEffect_BufferType ** bufferTypeArray)290 ImageEffect_ErrorCode OH_EffectFilterInfo_GetSupportedBufferTypes(OH_EffectFilterInfo *info, uint32_t *size,
291     ImageEffect_BufferType **bufferTypeArray)
292 {
293     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
294         "InfoGetSupportedBufferTypes: input parameter info is null!");
295     CHECK_AND_RETURN_RET_LOG(size != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
296         "InfoGetSupportedBufferTypes: input parameter size is invalid!");
297     CHECK_AND_RETURN_RET_LOG(bufferTypeArray != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
298         "InfoGetSupportedBufferTypes: input parameter bufferTypeArray is null!");
299 
300     if (info->supportedBufferTypes.empty()) {
301         *size = 0;
302         *bufferTypeArray = nullptr;
303         return ImageEffect_ErrorCode::EFFECT_SUCCESS;
304     }
305 
306     auto bufferTypeRealSize = static_cast<uint32_t>(info->supportedBufferTypes.size());
307     if (bufferTypeRealSize > info->bufferTypeArraySize && info->effectBufferType != nullptr) {
308         delete[] info->effectBufferType;
309         info->effectBufferType = nullptr;
310         info->bufferTypeArraySize = 0;
311     }
312 
313     if (info->effectBufferType == nullptr) {
314         std::unique_ptr<ImageEffect_BufferType[]> bufferType =
315             std::make_unique<ImageEffect_BufferType[]>(bufferTypeRealSize);
316         info->effectBufferType = bufferType.release();
317         info->bufferTypeArraySize = bufferTypeRealSize;
318     }
319 
320     uint32_t index = 0;
321     for (const auto &bufferType : info->supportedBufferTypes) {
322         if (index >= info->bufferTypeArraySize) {
323             EFFECT_LOGW("supportedBufferTypes size over bufferTypeArraySize! supportedBufferTypesSize=%{public}zu, "
324                 "bufferTypeArraySize=%{public}d", info->supportedBufferTypes.size(), info->bufferTypeArraySize);
325             break;
326         }
327         info->effectBufferType[index] = bufferType;
328         index++;
329     }
330     *size = index;
331     *bufferTypeArray = info->effectBufferType;
332 
333     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
334 }
335 
336 EFFECT_EXPORT
OH_EffectFilterInfo_SetSupportedFormats(OH_EffectFilterInfo * info,uint32_t size,ImageEffect_Format * formatArray)337 ImageEffect_ErrorCode OH_EffectFilterInfo_SetSupportedFormats(OH_EffectFilterInfo *info, uint32_t size,
338     ImageEffect_Format *formatArray)
339 {
340     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
341         "InfoSetSupportedFormats: input parameter info is null!");
342     CHECK_AND_RETURN_RET_LOG(size > 0, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
343         "InfoSetSupportedFormats: input parameter size is invalid! size=%{public}d", size);
344     CHECK_AND_RETURN_RET_LOG(formatArray != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
345         "InfoSetSupportedFormats: input parameter formatArray is null!");
346     EFFECT_LOGD("Set supported formats. size=%{public}d", size);
347     info->supportedFormats.clear();
348     for (uint32_t index = 0; index < size; index++) {
349         info->supportedFormats.emplace(formatArray[index]);
350     }
351     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
352 }
353 
354 EFFECT_EXPORT
OH_EffectFilterInfo_GetSupportedFormats(OH_EffectFilterInfo * info,uint32_t * size,ImageEffect_Format ** formatArray)355 ImageEffect_ErrorCode OH_EffectFilterInfo_GetSupportedFormats(OH_EffectFilterInfo *info, uint32_t *size,
356     ImageEffect_Format **formatArray)
357 {
358     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
359         "InfoGetSupportedFormats: input parameter info is null!");
360     CHECK_AND_RETURN_RET_LOG(size != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
361         "InfoGetSupportedFormats: input parameter size is invalid!");
362     CHECK_AND_RETURN_RET_LOG(formatArray != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
363         "InfoGetSupportedFormats: input parameter formatArray is null!");
364 
365     if (info->supportedFormats.empty()) {
366         *size = 0;
367         *formatArray = nullptr;
368         return ImageEffect_ErrorCode::EFFECT_SUCCESS;
369     }
370 
371     auto formatsRealSize = static_cast<uint32_t>(info->supportedFormats.size());
372     if (formatsRealSize > info->formatArraySize && info->effectFormat != nullptr) {
373         delete[] info->effectFormat;
374         info->effectFormat = nullptr;
375         info->formatArraySize = 0;
376     }
377 
378     if (info->effectFormat == nullptr) {
379         std::unique_ptr<ImageEffect_Format []> bufferType = std::make_unique<ImageEffect_Format[]>(formatsRealSize);
380         info->effectFormat = bufferType.release();
381         info->formatArraySize = formatsRealSize;
382     }
383 
384     uint32_t index = 0;
385     for (const auto &format : info->supportedFormats) {
386         if (index >= info->formatArraySize) {
387             EFFECT_LOGW("supportedFormats size over formatArraySize! supportedFormatsSize=%{public}zu, "
388                 "formatArraySize=%{public}d", info->supportedFormats.size(), info->formatArraySize);
389             break;
390         }
391         info->effectFormat[index] = format;
392         index++;
393     }
394     *size = index;
395     *formatArray = info->effectFormat;
396 
397     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
398 }
399 
400 EFFECT_EXPORT
OH_EffectFilterInfo_Release(OH_EffectFilterInfo * info)401 ImageEffect_ErrorCode OH_EffectFilterInfo_Release(OH_EffectFilterInfo *info)
402 {
403     EFFECT_LOGD("Filter release info.");
404     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
405         "ReleaseInfo: input parameter info is null!");
406     delete (info);
407     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
408 }
409 
410 EFFECT_EXPORT
OH_EffectBufferInfo_Create()411 OH_EffectBufferInfo *OH_EffectBufferInfo_Create()
412 {
413     std::unique_ptr<OH_EffectBufferInfo> info = std::make_unique<OH_EffectBufferInfo>();
414     return info.release();
415 }
416 
417 EFFECT_EXPORT
OH_EffectBufferInfo_SetAddr(OH_EffectBufferInfo * info,void * addr)418 ImageEffect_ErrorCode OH_EffectBufferInfo_SetAddr(OH_EffectBufferInfo *info, void *addr)
419 {
420     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
421         "BufferInfoSetAddr: input parameter info is null!");
422     CHECK_AND_RETURN_RET_LOG(addr != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
423         "BufferInfoSetAddr: input parameter addr is null!");
424     EFFECT_LOGD("Set buffer info addr.");
425     info->addr = addr;
426     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
427 }
428 
429 EFFECT_EXPORT
OH_EffectBufferInfo_GetAddr(OH_EffectBufferInfo * info,void ** addr)430 ImageEffect_ErrorCode OH_EffectBufferInfo_GetAddr(OH_EffectBufferInfo *info, void **addr)
431 {
432     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
433         "BufferInfoGetAddr: input parameter info is null!");
434     CHECK_AND_RETURN_RET_LOG(addr != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
435         "BufferInfoGetAddr: input parameter addr is null!");
436 
437     *addr = info->addr;
438     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
439 }
440 
441 EFFECT_EXPORT
OH_EffectBufferInfo_SetWidth(OH_EffectBufferInfo * info,int32_t width)442 ImageEffect_ErrorCode OH_EffectBufferInfo_SetWidth(OH_EffectBufferInfo *info, int32_t width)
443 {
444     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
445         "BufferInfoSetWidth: input parameter info is null!");
446     EFFECT_LOGD("BufferInfoSetWidth: width=%{public}d", width);
447     info->width = width;
448     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
449 }
450 
451 EFFECT_EXPORT
OH_EffectBufferInfo_GetWidth(OH_EffectBufferInfo * info,int32_t * width)452 ImageEffect_ErrorCode OH_EffectBufferInfo_GetWidth(OH_EffectBufferInfo *info, int32_t *width)
453 {
454     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
455         "BufferInfoGetWidth: input parameter info is null!");
456     CHECK_AND_RETURN_RET_LOG(width != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
457         "BufferInfoGetWidth: input parameter width is null!");
458 
459     *width = info->width;
460     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
461 }
462 
463 EFFECT_EXPORT
OH_EffectBufferInfo_SetHeight(OH_EffectBufferInfo * info,int32_t height)464 ImageEffect_ErrorCode OH_EffectBufferInfo_SetHeight(OH_EffectBufferInfo *info, int32_t height)
465 {
466     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
467         "BufferInfoSetHeight: input parameter info is null!");
468     EFFECT_LOGD("BufferInfoSetHeight: height=%{public}d", height);
469     info->height = height;
470     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
471 }
472 
473 EFFECT_EXPORT
OH_EffectBufferInfo_GetHeight(OH_EffectBufferInfo * info,int32_t * height)474 ImageEffect_ErrorCode OH_EffectBufferInfo_GetHeight(OH_EffectBufferInfo *info, int32_t *height)
475 {
476     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
477         "BufferInfoGetHeight: input parameter info is null!");
478     CHECK_AND_RETURN_RET_LOG(height != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
479         "BufferInfoGetHeight: input parameter height is null!");
480 
481     *height = info->height;
482     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
483 }
484 
485 EFFECT_EXPORT
OH_EffectBufferInfo_SetRowSize(OH_EffectBufferInfo * info,int32_t rowSize)486 ImageEffect_ErrorCode OH_EffectBufferInfo_SetRowSize(OH_EffectBufferInfo *info, int32_t rowSize)
487 {
488     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
489         "BufferInfoSetRowSize: input parameter info is null!");
490     EFFECT_LOGD("BufferInfoSetRowSize: rowSize=%{public}d", rowSize);
491     info->rowSize = rowSize;
492     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
493 }
494 
495 EFFECT_EXPORT
OH_EffectBufferInfo_GetRowSize(OH_EffectBufferInfo * info,int32_t * rowSize)496 ImageEffect_ErrorCode OH_EffectBufferInfo_GetRowSize(OH_EffectBufferInfo *info, int32_t *rowSize)
497 {
498     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
499         "BufferInfoGetRowSize: input parameter info is null!");
500     CHECK_AND_RETURN_RET_LOG(rowSize != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
501         "BufferInfoGetRowSize: input parameter rowSize is null!");
502 
503     *rowSize = info->rowSize;
504     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
505 }
506 
507 EFFECT_EXPORT
OH_EffectBufferInfo_SetEffectFormat(OH_EffectBufferInfo * info,ImageEffect_Format format)508 ImageEffect_ErrorCode OH_EffectBufferInfo_SetEffectFormat(OH_EffectBufferInfo *info, ImageEffect_Format format)
509 {
510     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
511         "BufferInfoSetEffectFormat: input parameter info is null!");
512     EFFECT_LOGD("BufferInfoSetEffectFormat: format=%{public}d", format);
513     info->format = format;
514     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
515 }
516 
517 EFFECT_EXPORT
OH_EffectBufferInfo_GetEffectFormat(OH_EffectBufferInfo * info,ImageEffect_Format * format)518 ImageEffect_ErrorCode OH_EffectBufferInfo_GetEffectFormat(OH_EffectBufferInfo *info, ImageEffect_Format *format)
519 {
520     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
521         "BufferInfoGetEffectFormat: input parameter info is null!");
522     CHECK_AND_RETURN_RET_LOG(format != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
523         "BufferInfoGetEffectFormat: input parameter format is null!");
524 
525     *format = info->format;
526     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
527 }
528 
529 EFFECT_EXPORT
OH_EffectBufferInfo_SetTimestamp(OH_EffectBufferInfo * info,int64_t timestamp)530 ImageEffect_ErrorCode OH_EffectBufferInfo_SetTimestamp(OH_EffectBufferInfo *info, int64_t timestamp)
531 {
532     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
533         "BufferInfoSetTimestamp: input parameter info is null!");
534     EFFECT_LOGD("BufferInfoSetTimestamp: timestamp=%{public}lld", static_cast<long long>(timestamp));
535     info->timestamp = timestamp;
536     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
537 }
538 
539 EFFECT_EXPORT
OH_EffectBufferInfo_GetTimestamp(OH_EffectBufferInfo * info,int64_t * timestamp)540 ImageEffect_ErrorCode OH_EffectBufferInfo_GetTimestamp(OH_EffectBufferInfo *info, int64_t *timestamp)
541 {
542     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
543         "BufferInfoGetTimestamp: input parameter info is null!");
544     CHECK_AND_RETURN_RET_LOG(timestamp != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
545         "BufferInfoGetTimestamp: input parameter timestamp is null!");
546 
547     *timestamp = info->timestamp;
548     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
549 }
550 
551 EFFECT_EXPORT
OH_EffectBufferInfo_Release(OH_EffectBufferInfo * info)552 ImageEffect_ErrorCode OH_EffectBufferInfo_Release(OH_EffectBufferInfo *info)
553 {
554     EFFECT_LOGD("Filter release buffer info.");
555     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
556         "EffectFilter ReleaseBufferInfo: input parameter info is null!");
557     delete (info);
558     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
559 }
560 
561 EFFECT_EXPORT
OH_EffectFilter_Create(const char * name)562 OH_EffectFilter *OH_EffectFilter_Create(const char *name)
563 {
564     CHECK_AND_RETURN_RET_LOG(name != nullptr, nullptr, "FilterCreate: input parameter name is null!");
565     CHECK_AND_RETURN_RET_LOG(strlen(name) < MAX_CHAR_LEN, nullptr,
566         "FilterCreate: the length of input parameter name is too long! len = %{public}zu", strlen(name));
567     EFFECT_LOGI("Filter create. name=%{public}s", name);
568     std::unique_ptr<OH_EffectFilter> nativeEFilter = std::make_unique<OH_EffectFilter>();
569     std::shared_ptr<EFilter> filter = EFilterFactory::Instance()->Create(name, nativeEFilter.get());
570     if (filter == nullptr) {
571         EFFECT_LOGW("FilterCreate: create filter fail. name=%{public}s not exist!", name);
572         return nullptr;
573     }
574     nativeEFilter->filter_ = filter;
575     return nativeEFilter.release();
576 }
577 
578 EFFECT_EXPORT
OH_EffectFilter_SetValue(OH_EffectFilter * filter,const char * key,const ImageEffect_Any * value)579 ImageEffect_ErrorCode OH_EffectFilter_SetValue(OH_EffectFilter *filter, const char *key, const ImageEffect_Any *value)
580 {
581     CHECK_AND_RETURN_RET_LOG(filter != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
582         "FilterSetValue: input parameter filter is null!");
583     CHECK_AND_RETURN_RET_LOG(key != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
584         "FilterSetValue: input parameter key is null!");
585     CHECK_AND_RETURN_RET_LOG(strlen(key) < MAX_CHAR_LEN, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
586         "FilterSetValue: the length of input parameter key is too long! len = %{public}zu", strlen(key));
587     CHECK_AND_RETURN_RET_LOG(value != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
588         "FilterSetValue: input parameter value is null!");
589     EFFECT_LOGI("Effect filter set value. key=%{public}s", key);
590 
591     Plugin::Any any;
592     ErrorCode result = NativeCommonUtils::ParseOHAny(value, any);
593     if (result != ErrorCode::SUCCESS) {
594         EFFECT_LOGE("FilterSetValue: parse any fail! result=%{public}d, dataType=%{public}d", result, value->dataType);
595         return ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID;
596     }
597 
598     result = filter->filter_->SetValue(key, any);
599     if (result != ErrorCode::SUCCESS) {
600         EFFECT_LOGE("FilterSetValue: set value fail! result=%{public}d, key=%{public}s, dataType=%{public}d", result,
601             key, value->dataType);
602         return ImageEffect_ErrorCode::EFFECT_KEY_ERROR;
603     }
604 
605     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
606 }
607 
608 EFFECT_EXPORT
OH_EffectFilter_GetValue(OH_EffectFilter * nativeEFilter,const char * key,ImageEffect_Any * value)609 ImageEffect_ErrorCode OH_EffectFilter_GetValue(OH_EffectFilter *nativeEFilter, const char *key, ImageEffect_Any *value)
610 {
611     CHECK_AND_RETURN_RET_LOG(nativeEFilter != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
612         "FilterGetValue: input parameter nativeEFilter is null!");
613     CHECK_AND_RETURN_RET_LOG(key != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
614         "FilterGetValue: input parameter key is null!");
615     CHECK_AND_RETURN_RET_LOG(strlen(key) < MAX_CHAR_LEN, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
616         "FilterGetValue: the length of input parameter key is too long! len = %{public}zu", strlen(key));
617     CHECK_AND_RETURN_RET_LOG(value != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
618         "FilterGetValue: input parameter value is null!");
619     EFFECT_LOGD("Effect filter get value. key=%{public}s", key);
620 
621     if (strcmp("FILTER_NAME", key) == 0) {
622         value->dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_PTR;
623         value->dataValue.ptrValue = static_cast<void *>(const_cast<char *>(nativeEFilter->filter_->GetName().c_str()));
624         return ImageEffect_ErrorCode::EFFECT_SUCCESS;
625     }
626 
627     Plugin::Any any;
628     ErrorCode result = nativeEFilter->filter_->GetValue(key, any);
629     if (result != ErrorCode::SUCCESS) {
630         EFFECT_LOGE("FilterGetValue: get value fail! result=%{public}d, key=%{public}s", result, key);
631         return ImageEffect_ErrorCode::EFFECT_KEY_ERROR;
632     }
633 
634     result = NativeCommonUtils::SwitchToOHAny(any, value);
635     if (result != ErrorCode::SUCCESS) {
636         EFFECT_LOGE("FilterGetValue: get value fail! result=%{public}d, key=%{public}s", result, key);
637         return ImageEffect_ErrorCode::EFFECT_UNKNOWN;
638     }
639 
640     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
641 }
642 
643 EFFECT_EXPORT
OH_EffectFilter_Register(const OH_EffectFilterInfo * info,const ImageEffect_FilterDelegate * delegate)644 ImageEffect_ErrorCode OH_EffectFilter_Register(const OH_EffectFilterInfo *info,
645     const ImageEffect_FilterDelegate *delegate)
646 {
647     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
648         "RegisterFilter: input parameter info is null!");
649     CHECK_AND_RETURN_RET_LOG(delegate != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
650         "RegisterFilter: input parameter delegate is null!");
651     EFFECT_LOGI("Filter register. filterName=%{public}s", info->filterName.c_str());
652     std::shared_ptr<FilterDelegate> effectDelegate = std::make_shared<FilterDelegate>(info, delegate);
653 
654     std::shared_ptr<EffectInfo> effectInfo = std::make_shared<EffectInfo>();
655     NativeCommonUtils::SwitchToEffectInfo(info, effectInfo);
656     EFilterFactory::Instance()->RegisterDelegate(info->filterName, effectDelegate, effectInfo);
657 
658     EventInfo eventInfo = {
659         .filterName = info->filterName,
660         .supportedFormats = NativeCommonUtils::GetSupportedFormats(info),
661     };
662     EventReport::ReportHiSysEvent(REGISTER_CUSTOM_FILTER_STATISTIC, eventInfo);
663     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
664 }
665 
666 EFFECT_EXPORT
OH_EffectFilter_LookupFilters(const char * key)667 ImageEffect_FilterNames *OH_EffectFilter_LookupFilters(const char *key)
668 {
669     std::unique_lock<std::mutex> lock(filterMutex_);
670     CHECK_AND_RETURN_RET_LOG(key != nullptr, nullptr, "LookupFilters: input parameter key is null!");
671     CHECK_AND_RETURN_RET_LOG(strlen(key) < MAX_CHAR_LEN, nullptr,
672         "LookupFilters: the length of input parameter key is too long! len = %{public}zu", strlen(key));
673     EFFECT_LOGD("Lookup filters. key=%{public}s", key);
674 
675     std::string lookupKey = key;
676     std::vector<const char *> matchEFilter;
677     NativeCommonUtils::ParseLookupKey(lookupKey, matchEFilter);
678 
679     std::shared_ptr<ImageEffect_FilterNames> filterNames = std::make_shared<ImageEffect_FilterNames>();
680     filterNames->size = matchEFilter.size();
681     if (filterNames->size != 0) {
682         const char **buffer = (const char **)malloc(matchEFilter.size() * sizeof(const char *));
683         if (buffer != nullptr) {
684             for (size_t i = 0; i < matchEFilter.size(); i++) {
685                 buffer[i] = matchEFilter[i];
686             }
687             filterNames->nameList = buffer;
688         }
689     }
690     sOHFilterNames.emplace_back(filterNames);
691 
692     return filterNames.get();
693 }
694 
695 EFFECT_EXPORT
OH_EffectFilter_ReleaseFilterNames()696 void OH_EffectFilter_ReleaseFilterNames()
697 {
698     std::unique_lock<std::mutex> lock(filterMutex_);
699     EFFECT_LOGI("Release filter names.");
700     for (const auto &filterNames : sOHFilterNames) {
701         if (filterNames == nullptr) {
702             continue;
703         }
704         free(filterNames->nameList);
705     }
706     sOHFilterNames.clear();
707 }
708 
709 EFFECT_EXPORT
OH_EffectFilter_LookupFilterInfo(const char * name,OH_EffectFilterInfo * info)710 ImageEffect_ErrorCode OH_EffectFilter_LookupFilterInfo(const char *name, OH_EffectFilterInfo *info)
711 {
712     CHECK_AND_RETURN_RET_LOG(name != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
713         "LookupFilterInfo: input parameter name is null!");
714     CHECK_AND_RETURN_RET_LOG(strlen(name) < MAX_CHAR_LEN, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
715         "LookupFilterInfo: the length of input parameter name is too long! len = %{public}zu", strlen(name));
716     CHECK_AND_RETURN_RET_LOG(info != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
717         "LookupFilterInfo: input parameter info is null!");
718     EFFECT_LOGD("Lookup filter info. name=%{public}s", name);
719 
720     std::shared_ptr<IFilterDelegate> filterDelegate = EFilterFactory::Instance()->GetDelegate(name);
721     if (filterDelegate != nullptr) {
722         auto effectInfo = static_cast<OH_EffectFilterInfo *>(filterDelegate->GetEffectInfo());
723         CHECK_AND_RETURN_RET_LOG(effectInfo != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
724             "LookupFilterInfo: filter delegate get effect info is null! name=%{public}s", name);
725         *info = *effectInfo;
726         return ImageEffect_ErrorCode::EFFECT_SUCCESS;
727     }
728 
729     std::shared_ptr<EffectInfo> effectInfo = EFilterFactory::Instance()->GetEffectInfo(name);
730     CHECK_AND_RETURN_RET_LOG(effectInfo != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
731         "LookupFilterInfo: lookup fail! name=%{public}s", name);
732 
733     info->filterName = name;
734     NativeCommonUtils::SwitchToOHEffectInfo(effectInfo.get(), info);
735     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
736 }
737 
738 EFFECT_EXPORT
OH_EffectFilter_Render(OH_EffectFilter * filter,OH_PixelmapNative * inputPixelmap,OH_PixelmapNative * outputPixelmap)739 ImageEffect_ErrorCode OH_EffectFilter_Render(OH_EffectFilter *filter, OH_PixelmapNative *inputPixelmap,
740     OH_PixelmapNative *outputPixelmap)
741 {
742     EFFECT_LOGI("Filter render.");
743     CHECK_AND_RETURN_RET_LOG(filter != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
744         "FilterRender: input parameter filter is null!");
745     if (filter->filter_->IsTextureInput()) {
746         std::shared_ptr<EffectBuffer> tempEffectBuffer = nullptr;
747         ErrorCode res = filter->filter_->Render(tempEffectBuffer, tempEffectBuffer);
748         CHECK_AND_RETURN_RET_LOG(res == ErrorCode::SUCCESS, ImageEffect_ErrorCode::EFFECT_UNKNOWN,
749             "FilterRender: filter render fail! errorCode:%{public}d", res);
750         return ImageEffect_ErrorCode::EFFECT_SUCCESS;
751     }
752     CHECK_AND_RETURN_RET_LOG(inputPixelmap != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
753         "FilterRender: input parameter inputPixelmap is null!");
754     CHECK_AND_RETURN_RET_LOG(outputPixelmap != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
755         "FilterRender: input parameter outputPixelmap is null!");
756 
757     PixelMap *input = NativeCommonUtils::GetPixelMapFromOHPixelmap(inputPixelmap);
758     PixelMap *output = NativeCommonUtils::GetPixelMapFromOHPixelmap(outputPixelmap);
759 
760     std::shared_ptr<EffectBuffer> inEffectBuffer = nullptr;
761     ErrorCode result = CommonUtils::LockPixelMap(input, inEffectBuffer);
762     if (result != ErrorCode::SUCCESS || inEffectBuffer == nullptr) {
763         EFFECT_LOGE("FilterRender: lock input native pixelMap error! errorCode:%{public}d", result);
764         CommonUtils::UnlockPixelMap(input);
765         return ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID;
766     }
767 
768     std::shared_ptr<EffectBuffer> outEffectBuffer = nullptr;
769     result = CommonUtils::LockPixelMap(output, outEffectBuffer);
770     if (result != ErrorCode::SUCCESS || outEffectBuffer == nullptr) {
771         EFFECT_LOGE("FilterRender: lock output native pixelMap error! errorCode:%{public}d", result);
772         CommonUtils::UnlockPixelMap(output);
773         return ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID;
774     }
775 
776     filter->filter_->PreRender(inEffectBuffer->bufferInfo_->formatType_);
777     result = filter->filter_->Render(inEffectBuffer, outEffectBuffer);
778     CommonUtils::UnlockPixelMap(input);
779     CommonUtils::UnlockPixelMap(output);
780     CHECK_AND_RETURN_RET_LOG(result == ErrorCode::SUCCESS, ImageEffect_ErrorCode::EFFECT_UNKNOWN,
781         "FilterRender: filter render fail! errorCode:%{public}d", result);
782 
783     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
784 }
785 
786 EFFECT_EXPORT
OH_EffectFilter_Release(OH_EffectFilter * filter)787 ImageEffect_ErrorCode OH_EffectFilter_Release(OH_EffectFilter *filter)
788 {
789     EFFECT_LOGI("Effect filter release.");
790     CHECK_AND_RETURN_RET_LOG(filter != nullptr, ImageEffect_ErrorCode::EFFECT_ERROR_PARAM_INVALID,
791         "FilterRelease: input parameter imageEffect is null!");
792     delete (filter);
793     return ImageEffect_ErrorCode::EFFECT_SUCCESS;
794 }
795 #ifdef __cplusplus
796 }
797 #endif