• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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