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