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