1 /*
2  * Copyright (c) 2020-2021 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 "acelite_config.h"
17 #if (FEATURE_COMPONENT_CAMERA == 1)
18 
19 #include "camera_component.h"
20 #include <climits>
21 #include <fstream>
22 #include <sstream>
23 #include <string>
24 #include "ability_env.h"
25 #include "ace_log.h"
26 #include "ace_mem_base.h"
27 #include "js_async_work.h"
28 #include "key_parser.h"
29 #include "keys.h"
30 #include <sys/time.h>
31 
32 using namespace std;
33 
34 namespace OHOS {
35 namespace ACELite {
36 jerry_value_t CameraComponent::successCallback_;
37 jerry_value_t CameraComponent::failCallback_;
38 jerry_value_t CameraComponent::completeCallback_;
39 jerry_value_t CameraComponent::jsContext_;
40 bool CameraComponent::lastCaptureCompleted_ = true;
41 
42 const char * const CameraComponent::TAKE_PHOTO = "takePhoto";
43 const uint32_t CameraComponent::IMAG_W_PIXELS = 1920;
44 const uint32_t CameraComponent::IMAG_H_PIXELS = 1080;
45 const int32_t CameraComponent::IMAG_QFACTOR_LOW = 50;
46 const int32_t CameraComponent::IMAG_QFACTOR_NORMAL = 85;
47 const int32_t CameraComponent::IMAG_QFACTOR_HIGH = 90;
48 
OnFrameFinished(Media::Camera & camera,Media::FrameConfig & frameConfig,Media::FrameResult & frameResult)49 void FrameCallback::OnFrameFinished(Media::Camera &camera,
50                                     Media::FrameConfig &frameConfig,
51                                     Media::FrameResult &frameResult)
52 {
53     if (frameConfig.GetFrameConfigType() != Media::FRAME_CONFIG_CAPTURE) {
54         CameraComponent::ReleaseStaticResources();
55         return;
56     }
57     auto surfaceList = frameConfig.GetSurfaces();
58     if (surfaceList.empty()) {
59         CameraComponent::ReleaseStaticResources();
60         return;
61     }
62     Surface *surface = surfaceList.front();
63     SurfaceBuffer *buffer = (surface == nullptr) ? nullptr : surface->AcquireBuffer();
64     if (buffer == nullptr) {
65         CameraComponent::ReleaseStaticResources();
66         return;
67     }
68     string *filePath = CreateFilePath();
69     if (filePath == nullptr) {
70         surface->ReleaseBuffer(buffer);
71         CameraComponent::ReleaseStaticResources();
72         return;
73     }
74 
75     bool writeSuccess = WriteCapture(*filePath, static_cast<char *>(buffer->GetVirAddr()), buffer->GetSize());
76     CallbackData *callbackData = new CallbackData();
77     if ((!writeSuccess) || (callbackData == nullptr)) {
78         delete filePath;
79         filePath = nullptr;
80         surface->ReleaseBuffer(buffer);
81         CameraComponent::ReleaseStaticResources();
82         if (callbackData != nullptr) {
83             delete callbackData;
84             callbackData = nullptr;
85         }
86         return;
87     }
88 
89     callbackData->isSucceed_ = true;
90     callbackData->uri_ = filePath;
91     if (!JsAsyncWork::DispatchAsyncWork(ExecuteJsCallback, callbackData)) {
92         delete callbackData;
93         callbackData = nullptr;
94         CameraComponent::ReleaseStaticResources();
95     }
96     surface->ReleaseBuffer(buffer);
97 }
98 
OnFrameError(Media::Camera & camera,Media::FrameConfig & frameConfig,int32_t errorCode,Media::FrameResult & frameResult)99 void FrameCallback::OnFrameError(Media::Camera &camera,
100                                  Media::FrameConfig &frameConfig,
101                                  int32_t errorCode,
102                                  Media::FrameResult &frameResult)
103 {
104     CallbackData *callbackData = new CallbackData();
105     if (callbackData == nullptr) {
106         CameraComponent::ReleaseStaticResources();
107         return;
108     }
109     callbackData->isSucceed_ = false;
110     callbackData->errorCode_ = errorCode;
111     callbackData->errorMsg_ = new string("takePhoto failed due to frame error!");
112     if (!JsAsyncWork::DispatchAsyncWork(ExecuteJsCallback, callbackData)) {
113         delete callbackData;
114         callbackData = nullptr;
115         CameraComponent::ReleaseStaticResources();
116     }
117 }
118 
ExecuteJsCallback(void * data)119 void FrameCallback::ExecuteJsCallback(void *data)
120 {
121     CallbackData *callbackData = static_cast<CallbackData *>(data);
122     if (callbackData == nullptr) {
123         CameraComponent::ReleaseStaticResources();
124         return;
125     }
126 
127     if ((callbackData->isSucceed_) && (callbackData->uri_ != nullptr)) {
128         CallSuccessFunc(callbackData->uri_->c_str());
129         CallCompleteFunc();
130     } else if ((!callbackData->isSucceed_) && (callbackData->errorMsg_ != nullptr)) {
131         CallFailFunc(callbackData->errorCode_, callbackData->errorMsg_->c_str());
132         CallCompleteFunc();
133     }
134     delete callbackData;
135     callbackData = nullptr;
136     CameraComponent::ReleaseStaticResources();
137 }
138 
CreateFilePath() const139 string *FrameCallback::CreateFilePath() const
140 {
141     const char *dataPath = GetDataPath();
142     if (dataPath == nullptr) {
143         HILOG_ERROR(HILOG_MODULE_ACE, "FrameCallback: get data path failed!");
144         return nullptr;
145     }
146     char fullDataPath[PATH_MAX + 1] = {0};
147     if (realpath(dataPath, fullDataPath) == nullptr) {
148         HILOG_ERROR(HILOG_MODULE_ACE, "FrameCallback: invalid data path!");
149         return nullptr;
150     }
151 
152     string dataPathStr(fullDataPath);
153     string prefix = dataPathStr + "/Img_";
154     ostringstream oss;
155     struct timeval timeVal;
156     bool getTimeSuccess = false;
157     if (gettimeofday(&timeVal, nullptr) == 0) {
158         struct tm *ltm = localtime(&(timeVal.tv_sec));
159         if (ltm != nullptr) {
160             oss << prefix << (ltm->tm_year) << (ltm->tm_mon + 1) << ltm->tm_mday << "_" << ltm->tm_hour << ltm->tm_min
161                 << ltm->tm_sec << ".jpg";
162             getTimeSuccess = true;
163         }
164     }
165     if (!getTimeSuccess) {
166         oss << prefix << ".jpg";
167     }
168     return new string(oss.str());
169 }
170 
WriteCapture(string & filePath,const char * const buffer,const uint32_t size) const171 bool FrameCallback::WriteCapture(string &filePath, const char * const buffer, const uint32_t size) const
172 {
173     if (buffer == nullptr) {
174         HILOG_ERROR(HILOG_MODULE_ACE, "FrameCallback: write capture with null buffer!");
175         return false;
176     }
177     ofstream file(filePath);
178     if (!file.is_open()) {
179         HILOG_ERROR(HILOG_MODULE_ACE, "FrameCallback: open file failed when write capture!");
180         return false;
181     }
182     file.write(buffer, size);
183     if (file.fail() || file.bad()) {
184         HILOG_ERROR(HILOG_MODULE_ACE, "FrameCallback: write file failed when write capture!");
185         file.close();
186         return false;
187     }
188     file.close();
189     return true;
190 }
191 
CallSuccessFunc(const char * const uri)192 void FrameCallback::CallSuccessFunc(const char * const uri)
193 {
194     if (jerry_value_is_function(CameraComponent::successCallback_) && (uri != nullptr)) {
195         const char * const uriKey = "uri";
196         jerry_value_t arg = jerry_create_object();
197         JerrySetStringProperty(arg, uriKey, uri);
198         CallJSFunctionAutoRelease(CameraComponent::successCallback_, CameraComponent::jsContext_, &arg, 1);
199         jerry_release_value(arg);
200     }
201 }
202 
CallFailFunc(const int32_t errorCode,const char * const errorMsg)203 void FrameCallback::CallFailFunc(const int32_t errorCode, const char * const errorMsg)
204 {
205     if (jerry_value_is_function(CameraComponent::failCallback_) && (errorMsg != nullptr)) {
206         jerry_value_t erromsg = jerry_create_string(reinterpret_cast<const jerry_char_t *>(errorMsg));
207         jerry_value_t errocode = jerry_create_number(errorCode);
208         jerry_value_t failArg[] = {erromsg, errocode};
209         const uint8_t agrc = 2; // 2 arguments for fail callback
210         CallJSFunctionAutoRelease(CameraComponent::failCallback_, CameraComponent::jsContext_, failArg, agrc);
211         ReleaseJerryValue(erromsg, errocode, VA_ARG_END_FLAG);
212     }
213 }
214 
CallCompleteFunc()215 void FrameCallback::CallCompleteFunc()
216 {
217     if (jerry_value_is_function(CameraComponent::completeCallback_)) {
218         CallJSFunctionAutoRelease(CameraComponent::completeCallback_, CameraComponent::jsContext_, nullptr, 0);
219     }
220 }
221 
OnCreated(Media::Camera & camera)222 void CameraCallback::OnCreated(Media::Camera &camera)
223 {
224     frameCallback_ = make_unique<FrameCallback>();
225     Media::CameraConfig *config = Media::CameraConfig::CreateCameraConfig();
226     if (config == nullptr) {
227         HILOG_ERROR(HILOG_MODULE_ACE, "CameraCallback: create camera config failed!");
228         return;
229     }
230     config->SetFrameStateCallback(frameCallback_.get(), eventHandler_.get());
231     camera.Configure(*config);
232     camera_ = &camera;
233 
234     if (previewSurface_ == nullptr) {
235         HILOG_ERROR(HILOG_MODULE_ACE, "CameraCallback: fail to start preview due to null surface!");
236         return;
237     }
238     frameConfig_ = new Media::FrameConfig(Media::FRAME_CONFIG_PREVIEW);
239     if (frameConfig_ == nullptr) {
240         HILOG_ERROR(HILOG_MODULE_ACE, "CameraCallback: create frame config for preview failed!");
241         return;
242     }
243     frameConfig_->AddSurface(*previewSurface_);
244     camera.TriggerLoopingCapture(*frameConfig_);
245 }
246 
OnCreateFailed(const string cameraId,int32_t errorCode)247 void CameraCallback::OnCreateFailed(const string cameraId, int32_t errorCode)
248 {
249     HILOG_ERROR(HILOG_MODULE_ACE, "CameraCallback: camera:%{public}s unavailable, errorCode:%{public}d",
250                 cameraId.c_str(), errorCode);
251     if (jerry_value_is_function(errorCallback_)) {
252         const char * const detailKey = "detail";
253         const char * const detailValue = "camera unavailable";
254         const char * const errorCodeKey = "errorCode";
255         jerry_value_t arg = jerry_create_object();
256         JerrySetStringProperty(arg, detailKey, detailValue);
257         JerrySetNumberProperty(arg, errorCodeKey, errorCode);
258         CallJSFunctionAutoRelease(errorCallback_, UNDEFINED, &arg, 1);
259         jerry_release_value(arg);
260     }
261 }
262 
CameraComponent(jerry_value_t options,jerry_value_t children,AppStyleManager * styleManager)263 CameraComponent::CameraComponent(jerry_value_t options, jerry_value_t children, AppStyleManager *styleManager)
264     : Component(options, children, styleManager), cameraKit_(nullptr), frameConfig_(nullptr), captureSurface_(nullptr)
265 {
266     SetComponentName(K_CAMERA);
267     RegisterNamedFunction(TAKE_PHOTO, TakePhoto);
268 }
269 
CreateNativeViews()270 bool CameraComponent::CreateNativeViews()
271 {
272     cameraView_ = make_unique<UISurfaceView>();
273     captureSurface_ = Surface::CreateSurface();
274     if ((cameraView_ == nullptr) || (captureSurface_ == nullptr)) {
275         HILOG_ERROR(HILOG_MODULE_ACE, "CameraComponent: create camera view failed!");
276         return false;
277     }
278     cameraKit_ = Media::CameraKit::GetInstance();
279     cameraCallback_ = make_unique<CameraCallback>();
280     frameConfig_ = new Media::FrameConfig(Media::FRAME_CONFIG_CAPTURE);
281     if (frameConfig_ != nullptr) {
282         captureSurface_->SetWidthAndHeight(IMAG_W_PIXELS, IMAG_H_PIXELS);
283         captureSurface_->SetUsage(BUFFER_CONSUMER_USAGE_HARDWARE);
284         frameConfig_->AddSurface(*captureSurface_);
285     }
286     return true;
287 }
288 
ReleaseNativeViews()289 void CameraComponent::ReleaseNativeViews()
290 {
291     if (cameraCallback_ != nullptr) {
292         Media::Camera *camera = const_cast<Media::Camera *>(cameraCallback_->GetCameraInstance());
293         if (camera != nullptr) {
294             camera->StopLoopingCapture(-1);
295         }
296         cameraCallback_.reset();
297     }
298     if (frameConfig_ != nullptr) {
299         delete frameConfig_;
300         frameConfig_ = nullptr;
301     }
302     if (captureSurface_ != nullptr) {
303         delete captureSurface_;
304         captureSurface_ = nullptr;
305     }
306 }
307 
GetComponentRootView() const308 inline UIView *CameraComponent::GetComponentRootView() const
309 {
310     return static_cast<UIView *>(cameraView_.get());
311 }
312 
RegisterPrivateEventListener(uint16_t eventTypeId,jerry_value_t funcValue,bool isStopPropagation)313 bool CameraComponent::RegisterPrivateEventListener(uint16_t eventTypeId,
314                                                    jerry_value_t funcValue,
315                                                    bool isStopPropagation)
316 {
317     bool result = false;
318     switch (eventTypeId) {
319         case K_ERROR: {
320             if (cameraCallback_ != nullptr) {
321                 cameraCallback_->SetErrorCallback(funcValue);
322                 result = true;
323             }
324             break;
325         }
326         default:
327             break;
328     }
329     return result;
330 }
331 
PostRender()332 void CameraComponent::PostRender()
333 {
334     if ((cameraView_ == nullptr) || (cameraKit_ == nullptr) || (cameraCallback_ == nullptr)) {
335         HILOG_ERROR(HILOG_MODULE_ACE, "CameraComponent: post render failed due to null native object!");
336         return;
337     }
338     list<string> camList = cameraKit_->GetCameraIds();
339     if (camList.empty()) {
340         HILOG_ERROR(HILOG_MODULE_ACE, "CameraComponent: empty camera list!");
341         return;
342     }
343     const string cameraId = camList.front();
344     const Media::CameraAbility *ability = cameraKit_->GetCameraAbility(cameraId);
345     if (ability == nullptr) {
346         HILOG_ERROR(HILOG_MODULE_ACE, "CameraComponent: get camera ability failed!");
347         return;
348     }
349     bool isSizeSupported = false;
350     list<CameraPicSize> sizeList = ability->GetSupportedSizes(0);
351     for (auto &pic : sizeList) {
352         if (pic.width == IMAG_W_PIXELS && pic.height == IMAG_H_PIXELS) {
353             isSizeSupported = true;
354             break;
355         }
356     }
357     if (!isSizeSupported) {
358         HILOG_ERROR(HILOG_MODULE_ACE, "CameraComponent: capture resolution unsupported!");
359         return;
360     }
361 
362     Surface *previewSurface = cameraView_->GetSurface();
363     if (previewSurface != nullptr) {
364         previewSurface->SetWidthAndHeight(IMAG_W_PIXELS, IMAG_H_PIXELS);
365         previewSurface->SetUsage(BUFFER_CONSUMER_USAGE_HARDWARE);
366         cameraCallback_->SetPreviewSurface(*previewSurface);
367     }
368     cameraKit_->CreateCamera(cameraId, *cameraCallback_.get(), *cameraCallback_->GetEventHandler());
369 }
370 
TakePhoto(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t size)371 jerry_value_t CameraComponent::TakePhoto(const jerry_value_t func,
372                                          const jerry_value_t context,
373                                          const jerry_value_t args[],
374                                          const jerry_length_t size)
375 {
376     // capture processing flag
377     if (!lastCaptureCompleted_) {
378         HILOG_INFO(HILOG_MODULE_ACE,
379                    "Please wait until the last capture processing is over before trying to take a photo");
380         return UNDEFINED;
381     }
382     lastCaptureCompleted_ = false;
383     if (size != 1) {
384         HILOG_ERROR(HILOG_MODULE_ACE, "CameraComponent: call TakePhoto with invalid arguments!");
385         lastCaptureCompleted_ = true;
386         return UNDEFINED;
387     }
388 
389     UISurfaceView *cameraView = static_cast<UISurfaceView *>(ComponentUtils::GetViewFromBindingObject(context));
390     CameraComponent *component = static_cast<CameraComponent *>(ComponentUtils::GetComponentFromBindingObject(context));
391     if ((cameraView == nullptr) || (component == nullptr)) {
392         HILOG_ERROR(HILOG_MODULE_ACE, "CameraComponent: call TakePhoto failed due to null component object!");
393         lastCaptureCompleted_ = true;
394         return UNDEFINED;
395     }
396 
397     uint16_t length = 0;
398     const char * const qualityKey = "quality";
399     char *quality = JerryMallocStringProperty(args[0], qualityKey, length);
400     successCallback_ = jerryx_get_property_str(args[0], ATTR_SUCCESS);
401     failCallback_ = jerryx_get_property_str(args[0], ATTR_FAIL);
402     completeCallback_ = jerryx_get_property_str(args[0], ATTR_COMPLETE);
403     jsContext_ = jerry_acquire_value(context);
404 
405     if (!CaptureFrame(component, quality)) {
406         HILOG_ERROR(HILOG_MODULE_ACE, "CameraComponent: capture frame failed!");
407         ReleaseStaticResources();
408     }
409     ACE_FREE(quality);
410     return UNDEFINED;
411 }
412 
ReleaseStaticResources()413 void CameraComponent::ReleaseStaticResources()
414 {
415     ReleaseJerryValue(successCallback_, failCallback_, completeCallback_, jsContext_, VA_ARG_END_FLAG);
416     lastCaptureCompleted_ = true;
417 }
418 
CaptureFrame(const CameraComponent * component,const char * quality)419 bool CameraComponent::CaptureFrame(const CameraComponent *component, const char *quality)
420 {
421     Media::FrameConfig *frameConfig = component->GetFrameConfig();
422     if (frameConfig == nullptr) {
423         return false;
424     }
425     int32_t qfactor = IMAG_QFACTOR_NORMAL;
426     if (quality != nullptr) {
427         const char * const qualityLow = "low";
428         const char * const qualityHigh = "high";
429         if (strcmp(quality, qualityLow) == 0) {
430             qfactor = IMAG_QFACTOR_LOW;
431         } else if (strcmp(quality, qualityHigh) == 0) {
432             qfactor = IMAG_QFACTOR_HIGH;
433         }
434     }
435     frameConfig->SetParameter(PARAM_KEY_IMAGE_ENCODE_QFACTOR, qfactor);
436     const CameraCallback *cameraCallback = component->GetCameraCallback();
437     if (cameraCallback == nullptr) {
438         return false;
439     }
440     Media::Camera *camera = const_cast<Media::Camera *>(cameraCallback->GetCameraInstance());
441     if (camera == nullptr) {
442         return false;
443     }
444     return camera->TriggerSingleCapture(*frameConfig) == MEDIA_OK;
445 }
446 } // namespace ACELite
447 } // namespace OHOS
448 #endif // FEATURE_COMPONENT_CAMERA
449