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 #define MLOG_TAG "MultiStagesCaptureDeferredPhotoProcSessionCallback"
17
18 #include "multistages_capture_deferred_photo_proc_session_callback.h"
19
20 #include <sstream>
21
22 #include "database_adapter.h"
23 #include "file_utils.h"
24 #include "media_exif.h"
25 #include "media_file_utils.h"
26 #include "media_file_uri.h"
27 #include "media_log.h"
28 #include "medialibrary_asset_operations.h"
29 #include "medialibrary_errno.h"
30 #include "medialibrary_notify.h"
31 #include "medialibrary_object_utils.h"
32 #include "medialibrary_photo_operations.h"
33 #include "medialibrary_tracer.h"
34 #include "multistages_capture_manager.h"
35 #include "multistages_capture_dfx_result.h"
36 #include "multistages_capture_dfx_total_time.h"
37 #include "multistages_capture_request_task_manager.h"
38 #include "result_set_utils.h"
39 #include "media_change_effect.h"
40 #include "exif_metadata.h"
41
42 using namespace std;
43 using namespace OHOS::CameraStandard;
44
45 constexpr int32_t ORIENTATION_0 = 1;
46 constexpr int32_t ORIENTATION_90 = 6;
47 constexpr int32_t ORIENTATION_180 = 3;
48 constexpr int32_t ORIENTATION_270 = 8;
49
50 static const std::unordered_map<int, int> ORIENTATION_MAP = {
51 {0, ORIENTATION_0},
52 {90, ORIENTATION_90},
53 {180, ORIENTATION_180},
54 {270, ORIENTATION_270}
55 };
56
57 namespace OHOS {
58 namespace Media {
MultiStagesCaptureDeferredPhotoProcSessionCallback()59 MultiStagesCaptureDeferredPhotoProcSessionCallback::MultiStagesCaptureDeferredPhotoProcSessionCallback()
60 {}
61
~MultiStagesCaptureDeferredPhotoProcSessionCallback()62 MultiStagesCaptureDeferredPhotoProcSessionCallback::~MultiStagesCaptureDeferredPhotoProcSessionCallback()
63 {}
64
NotifyIfTempFile(shared_ptr<NativeRdb::ResultSet> resultSet)65 void MultiStagesCaptureDeferredPhotoProcSessionCallback::NotifyIfTempFile(shared_ptr<NativeRdb::ResultSet> resultSet)
66 {
67 if (resultSet == nullptr) {
68 MEDIA_WARN_LOG("resultSet is nullptr");
69 return;
70 }
71 string displayName = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
72 string filePath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
73 int32_t mediaType = GetInt32Val(MediaColumn::MEDIA_TYPE, resultSet);
74 int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
75 resultSet->Close();
76
77 auto watch = MediaLibraryNotify::GetInstance();
78 if (watch != nullptr) {
79 string extrUri = MediaFileUtils::GetExtraUri(displayName, filePath);
80 auto notifyUri = MediaFileUtils::GetUriByExtrConditions(ML_FILE_URI_PREFIX + MediaFileUri::GetMediaTypeUri(
81 static_cast<MediaType>(mediaType), MEDIA_API_VERSION_V10) + "/", to_string(fileId), extrUri);
82 MEDIA_DEBUG_LOG("notify %{public}s", MediaFileUtils::GetUriWithoutDisplayname(notifyUri).c_str());
83 watch->Notify(MediaFileUtils::GetUriWithoutDisplayname(notifyUri), NOTIFY_UPDATE);
84 }
85 }
86
UpdatePhotoQuality(const string & photoId)87 int32_t MultiStagesCaptureDeferredPhotoProcSessionCallback::UpdatePhotoQuality(const string &photoId)
88 {
89 MediaLibraryTracer tracer;
90 tracer.Start("UpdatePhotoQuality " + photoId);
91 MediaLibraryCommand updateCmd(OperationObject::FILESYSTEM_PHOTO, OperationType::UPDATE);
92 NativeRdb::ValuesBucket updateValues;
93 updateValues.PutInt(PhotoColumn::PHOTO_QUALITY, static_cast<int32_t>(MultiStagesPhotoQuality::FULL));
94 updateCmd.SetValueBucket(updateValues);
95 updateCmd.GetAbsRdbPredicates()->EqualTo(PhotoColumn::PHOTO_ID, photoId);
96 int32_t updatePhotoQualityResult = DatabaseAdapter::Update(updateCmd);
97
98 updateCmd.GetAbsRdbPredicates()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, false);
99 updateCmd.GetAbsRdbPredicates()->NotEqualTo(PhotoColumn::PHOTO_SUBTYPE,
100 to_string(static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)));
101 NativeRdb::ValuesBucket updateValuesDirty;
102 updateValuesDirty.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_NEW));
103 updateCmd.SetValueBucket(updateValuesDirty);
104 auto isDirtyResult = DatabaseAdapter::Update(updateCmd);
105 if (isDirtyResult < 0) {
106 MEDIA_WARN_LOG("update dirty flag fail, photoId: %{public}s", photoId.c_str());
107 }
108
109 return updatePhotoQualityResult;
110 }
111
UpdateCEAvailable(const string & photoId)112 void MultiStagesCaptureDeferredPhotoProcSessionCallback::UpdateCEAvailable(const string& photoId)
113 {
114 MediaLibraryCommand updateCEAvailableCmd(OperationObject::FILESYSTEM_PHOTO, OperationType::UPDATE);
115 NativeRdb::ValuesBucket updateCEAvailable;
116 updateCEAvailableCmd.GetAbsRdbPredicates()->EqualTo(PhotoColumn::PHOTO_ID, photoId);
117 updateCEAvailable.PutInt(PhotoColumn::PHOTO_CE_AVAILABLE,
118 static_cast<int32_t>(CloudEnhancementAvailableType::SUPPORT));
119 updateCEAvailableCmd.SetValueBucket(updateCEAvailable);
120 auto ceAvailableResult = DatabaseAdapter::Update(updateCEAvailableCmd);
121 if (ceAvailableResult < 0) {
122 MEDIA_WARN_LOG("update CE available fail, photoId: %{public}s", photoId.c_str());
123 return;
124 }
125 }
126
QuerySubType(const string & photoId)127 int32_t QuerySubType(const string &photoId)
128 {
129 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_PHOTO, OperationType::QUERY);
130 string where = PhotoColumn::PHOTO_ID + " = ? ";
131 vector<string> whereArgs { photoId };
132 cmd.GetAbsRdbPredicates()->SetWhereClause(where);
133 cmd.GetAbsRdbPredicates()->SetWhereArgs(whereArgs);
134 vector<string> columns { PhotoColumn::PHOTO_SUBTYPE };
135 auto resultSet = DatabaseAdapter::Query(cmd, columns);
136 if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
137 MEDIA_ERR_LOG("result set is empty, photoId: %{public}s", photoId.c_str());
138 return static_cast<int32_t>(PhotoSubType::CAMERA);
139 }
140 int32_t subType = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
141 resultSet->Close();
142 return subType == 0 ? static_cast<int32_t>(PhotoSubType::CAMERA) : subType;
143 }
144
OnError(const string & imageId,const DpsErrorCode error)145 void MultiStagesCaptureDeferredPhotoProcSessionCallback::OnError(const string &imageId, const DpsErrorCode error)
146 {
147 switch (error) {
148 case ERROR_SESSION_SYNC_NEEDED:
149 MultiStagesPhotoCaptureManager::GetInstance().SyncWithDeferredProcSession();
150 break;
151 case ERROR_IMAGE_PROC_INVALID_PHOTO_ID:
152 case ERROR_IMAGE_PROC_FAILED: {
153 MultiStagesPhotoCaptureManager::GetInstance().RemoveImage(imageId, false);
154 UpdatePhotoQuality(imageId);
155 MEDIA_ERR_LOG("error %{public}d, photoid: %{public}s", static_cast<int32_t>(error), imageId.c_str());
156 break;
157 }
158 default:
159 break;
160 }
161
162 if (error != ERROR_SESSION_SYNC_NEEDED) {
163 MultiStagesCaptureDfxResult::Report(imageId, static_cast<int32_t>(error),
164 static_cast<int32_t>(MultiStagesCaptureMediaType::Photo));
165 }
166 }
167
QueryPhotoData(const std::string & imageId)168 std::shared_ptr<NativeRdb::ResultSet> QueryPhotoData(const std::string &imageId)
169 {
170 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_PHOTO, OperationType::QUERY);
171 string where = PhotoColumn::PHOTO_ID + " = ? ";
172 vector<string> whereArgs { imageId };
173 cmd.GetAbsRdbPredicates()->SetWhereClause(where);
174 cmd.GetAbsRdbPredicates()->SetWhereArgs(whereArgs);
175 vector<string> columns { MediaColumn::MEDIA_ID, MediaColumn::MEDIA_FILE_PATH, PhotoColumn::PHOTO_EDIT_TIME,
176 MediaColumn::MEDIA_MIME_TYPE, PhotoColumn::PHOTO_SUBTYPE, PhotoColumn::MEDIA_TYPE, PhotoColumn::PHOTO_IS_TEMP,
177 PhotoColumn::PHOTO_ORIENTATION};
178 return DatabaseAdapter::Query(cmd, columns);
179 }
180
ProcessAndSaveHighQualityImage(const std::string & imageId,std::shared_ptr<Media::Picture> picture,std::shared_ptr<NativeRdb::ResultSet> resultSet,bool isCloudEnhancementAvailable)181 void MultiStagesCaptureDeferredPhotoProcSessionCallback::ProcessAndSaveHighQualityImage(
182 const std::string& imageId, std::shared_ptr<Media::Picture> picture,
183 std::shared_ptr<NativeRdb::ResultSet> resultSet, bool isCloudEnhancementAvailable)
184 {
185 if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
186 MEDIA_INFO_LOG("resultset is empty.");
187 return;
188 }
189 string data = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
190 bool isEdited = (GetInt64Val(PhotoColumn::PHOTO_EDIT_TIME, resultSet) > 0);
191 int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
192 string mimeType = GetStringVal(MediaColumn::MEDIA_MIME_TYPE, resultSet);
193 int32_t orientation = GetInt32Val(PhotoColumn::PHOTO_ORIENTATION, resultSet);
194 if (orientation != 0) {
195 auto metadata = picture->GetExifMetadata();
196 if (metadata == nullptr) {
197 MEDIA_ERR_LOG("metadata is null");
198 return;
199 }
200 auto imageSourceOrientation = ORIENTATION_MAP.find(orientation);
201 if (imageSourceOrientation == ORIENTATION_MAP.end()) {
202 MEDIA_ERR_LOG("imageSourceOrientation value is invalid.");
203 return;
204 }
205 metadata->SetValue(PHOTO_DATA_IMAGE_ORIENTATION, std::to_string(imageSourceOrientation->second));
206 }
207
208 // 裸picture落盘处理
209 int ret = MediaLibraryPhotoOperations::ProcessMultistagesPhotoForPicture(isEdited, data, picture, fileId, mimeType);
210 if (ret != E_OK) {
211 MEDIA_ERR_LOG("Save high quality image failed. ret: %{public}d, errno: %{public}d", ret, errno);
212 MultiStagesCaptureDfxResult::Report(imageId,
213 static_cast<int32_t>(MultiStagesCaptureResultErrCode::SAVE_IMAGE_FAIL),
214 static_cast<int32_t>(MultiStagesCaptureMediaType::Photo));
215 return;
216 }
217
218 MultiStagesPhotoCaptureManager::GetInstance().DealHighQualityPicture(imageId, std::move(picture), isEdited);
219 UpdateHighQualityPictureInfo(imageId, isCloudEnhancementAvailable);
220 MediaLibraryObjectUtils::ScanFileAsync(data, to_string(fileId), MediaLibraryApi::API_10);
221 NotifyIfTempFile(resultSet);
222
223 MultiStagesCaptureDfxTotalTime::GetInstance().Report(imageId);
224 MultiStagesCaptureDfxResult::Report(imageId, static_cast<int32_t>(MultiStagesCaptureResultErrCode::SUCCESS),
225 static_cast<int32_t>(MultiStagesCaptureMediaType::Photo));
226
227 // delete raw file
228 MultiStagesPhotoCaptureManager::GetInstance().RemoveImage(imageId, false);
229 MEDIA_INFO_LOG("MultistagesCapture yuv success photoid: %{public}s", imageId.c_str());
230 }
231
OnProcessImageDone(const std::string & imageId,std::shared_ptr<Media::Picture> picture,bool isCloudEnhancementAvailable)232 void MultiStagesCaptureDeferredPhotoProcSessionCallback::OnProcessImageDone(const std::string &imageId,
233 std::shared_ptr<Media::Picture> picture, bool isCloudEnhancementAvailable)
234 {
235 MediaLibraryTracer tracer;
236 tracer.Start("OnProcessImageDone " + imageId);
237 if (picture == nullptr || picture->GetMainPixel() == nullptr) {
238 tracer.Finish();
239 MEDIA_ERR_LOG("OnProcessImageDone picture is null");
240 return;
241 }
242 // 1. 分段式拍照已经处理完成,保存全质量图
243 MEDIA_INFO_LOG("yuv photoid: %{public}s, isCloudEnhancementAvailable: %{public}s enter", imageId.c_str(),
244 isCloudEnhancementAvailable?"true":"false");
245 tracer.Start("Query");
246 auto resultSet = QueryPhotoData(imageId);
247 if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
248 tracer.Finish();
249 MEDIA_INFO_LOG("result set is empty.");
250 // 高质量图先上来,直接保存
251 MultiStagesPhotoCaptureManager::GetInstance().DealHighQualityPicture(imageId, std::move(picture), false);
252 return;
253 }
254 tracer.Finish();
255 int32_t isTemp = GetInt32Val(PhotoColumn::PHOTO_IS_TEMP, resultSet);
256 if (isTemp) {
257 MultiStagesPhotoCaptureManager::GetInstance().DealHighQualityPicture(imageId, std::move(picture), false);
258 UpdateHighQualityPictureInfo(imageId, isCloudEnhancementAvailable);
259 return;
260 }
261 ProcessAndSaveHighQualityImage(imageId, picture, resultSet, isCloudEnhancementAvailable);
262 }
263
GetCommandByImageId(const std::string & imageId,MediaLibraryCommand & cmd)264 void MultiStagesCaptureDeferredPhotoProcSessionCallback::GetCommandByImageId(const std::string &imageId,
265 MediaLibraryCommand &cmd)
266 {
267 size_t slashIndex = imageId.rfind("/");
268 string where = "";
269 vector<string> whereArgs;
270 if (slashIndex != string::npos) {
271 string fileId = MediaFileUtils::GetIdFromUri(imageId);
272 where = PhotoColumn::MEDIA_ID + " = ? ";
273 whereArgs = { fileId };
274 }
275 cmd.GetAbsRdbPredicates()->SetWhereClause(where);
276 cmd.GetAbsRdbPredicates()->SetWhereArgs(whereArgs);
277 }
278
UpdateHighQualityPictureInfo(const std::string & imageId,bool isCloudEnhancementAvailable)279 void MultiStagesCaptureDeferredPhotoProcSessionCallback::UpdateHighQualityPictureInfo(const std::string &imageId,
280 bool isCloudEnhancementAvailable)
281 {
282 // 2. 更新数据库 photoQuality 到高质量
283 UpdatePhotoQuality(imageId);
284 // 3. update cloud enhancement avaiable
285 if (isCloudEnhancementAvailable) {
286 UpdateCEAvailable(imageId);
287 }
288 }
289
OnDeliveryLowQualityImage(const std::string & imageId,std::shared_ptr<Media::Picture> picture)290 void MultiStagesCaptureDeferredPhotoProcSessionCallback::OnDeliveryLowQualityImage(const std::string &imageId,
291 std::shared_ptr<Media::Picture> picture)
292 {
293 MEDIA_INFO_LOG("photoid: %{public}s", imageId.c_str());
294 if (picture != nullptr && picture->GetMainPixel() != nullptr) {
295 MEDIA_INFO_LOG("OnDeliveryLowQualityImage picture is not null");
296 } else {
297 MEDIA_INFO_LOG("OnDeliveryLowQualityImage picture is null");
298 return;
299 }
300 MediaLibraryTracer tracer;
301 tracer.Start("OnDeliveryLowQualityImage " + imageId);
302 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_PHOTO, OperationType::QUERY);
303 GetCommandByImageId(imageId, cmd);
304 vector<string> columns { MediaColumn::MEDIA_ID, MediaColumn::MEDIA_FILE_PATH, PhotoColumn::PHOTO_EDIT_TIME,
305 PhotoColumn::PHOTO_SUBTYPE, PhotoColumn::PHOTO_ID};
306 tracer.Start("Query");
307 auto resultSet = DatabaseAdapter::Query(cmd, columns);
308 if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
309 tracer.Finish();
310 MEDIA_INFO_LOG("result set is empty");
311 return;
312 }
313 tracer.Finish();
314 string photoId = GetStringVal(PhotoColumn::PHOTO_ID, resultSet);
315 string data = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
316 bool isEdited = (GetInt64Val(PhotoColumn::PHOTO_EDIT_TIME, resultSet) > 0);
317 resultSet->Close();
318 MultiStagesPhotoCaptureManager::GetInstance().DealLowQualityPicture(photoId, std::move(picture), isEdited);
319 MEDIA_INFO_LOG("save low quality image end");
320 }
321
OnProcessImageDone(const string & imageId,const uint8_t * addr,const long bytes,bool isCloudEnhancementAvailable)322 void MultiStagesCaptureDeferredPhotoProcSessionCallback::OnProcessImageDone(const string &imageId, const uint8_t *addr,
323 const long bytes, bool isCloudEnhancementAvailable)
324 {
325 CHECK_AND_RETURN_LOG((addr != nullptr) && (bytes != 0), "addr is nullptr or bytes(%{public}ld) is 0", bytes);
326 CHECK_AND_RETURN_LOG(MultiStagesCaptureRequestTaskManager::IsPhotoInProcess(imageId),
327 "this photo was delete or err photoId: %{public}s", imageId.c_str());
328 MediaLibraryTracer tracer;
329 tracer.Start("OnProcessImageDone " + imageId);
330 // 1. 分段式拍照已经处理完成,保存全质量图
331 MEDIA_INFO_LOG("photoid: %{public}s, bytes: %{public}ld, isCloudEnhancementAvailable: %{public}s enter",
332 imageId.c_str(), bytes, isCloudEnhancementAvailable?"true":"false");
333 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_PHOTO, OperationType::QUERY);
334 string where = PhotoColumn::PHOTO_ID + " = ? ";
335 vector<string> whereArgs { imageId };
336 cmd.GetAbsRdbPredicates()->SetWhereClause(where);
337 cmd.GetAbsRdbPredicates()->SetWhereArgs(whereArgs);
338 vector<string> columns { MediaColumn::MEDIA_ID, MediaColumn::MEDIA_FILE_PATH, PhotoColumn::PHOTO_EDIT_TIME,
339 PhotoColumn::MEDIA_NAME, PhotoColumn::MEDIA_TYPE, PhotoColumn::PHOTO_IS_TEMP };
340 tracer.Start("Query");
341 auto resultSet = DatabaseAdapter::Query(cmd, columns);
342 if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
343 tracer.Finish();
344 MEDIA_INFO_LOG("result set is empty");
345 MultiStagesCaptureDfxTotalTime::GetInstance().RemoveStartTime(imageId);
346 MultiStagesCaptureDfxResult::Report(imageId, static_cast<int32_t>(MultiStagesCaptureResultErrCode::SQL_ERR),
347 static_cast<int32_t>(MultiStagesCaptureMediaType::Photo));
348 return;
349 }
350 tracer.Finish();
351 string data = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
352 bool isEdited = (GetInt64Val(PhotoColumn::PHOTO_EDIT_TIME, resultSet) > 0);
353 int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
354 int ret = MediaLibraryPhotoOperations::ProcessMultistagesPhoto(isEdited, data, addr, bytes, fileId);
355 if (ret != E_OK) {
356 MEDIA_ERR_LOG("Save high quality image failed. ret: %{public}d, errno: %{public}d", ret, errno);
357 MultiStagesCaptureDfxResult::Report(imageId,
358 static_cast<int32_t>(MultiStagesCaptureResultErrCode::SAVE_IMAGE_FAIL),
359 static_cast<int32_t>(MultiStagesCaptureMediaType::Photo));
360 return;
361 }
362 // 2. 更新数据库 photoQuality 到高质量
363 UpdatePhotoQuality(imageId);
364 // 3. update cloud enhancement avaiable
365 if (isCloudEnhancementAvailable) {
366 UpdateCEAvailable(imageId);
367 }
368
369 MediaLibraryObjectUtils::ScanFileAsync(data, to_string(fileId), MediaLibraryApi::API_10);
370 NotifyIfTempFile(resultSet);
371
372 MultiStagesCaptureDfxTotalTime::GetInstance().Report(imageId);
373 MultiStagesCaptureDfxResult::Report(imageId, static_cast<int32_t>(MultiStagesCaptureResultErrCode::SUCCESS),
374 static_cast<int32_t>(MultiStagesCaptureMediaType::Photo));
375
376 // delete raw file
377 MultiStagesPhotoCaptureManager::GetInstance().RemoveImage(imageId, false);
378 MEDIA_INFO_LOG("success photoid: %{public}s", imageId.c_str());
379 }
380
OnStateChanged(const DpsStatusCode state)381 void MultiStagesCaptureDeferredPhotoProcSessionCallback::OnStateChanged(const DpsStatusCode state)
382 {
383 MEDIA_INFO_LOG("status: %{public}d", state);
384 }
385 } // namespace Media
386 } // namespace OHOS