• 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 #include "video_composition_callback_imp.h"
17 
18 #include "media_log.h"
19 #include "media_file_utils.h"
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include "medialibrary_errno.h"
24 #include "photo_file_utils.h"
25 #include "directory_ex.h"
26 
27 using std::string;
28 
29 namespace OHOS {
30 namespace Media {
31 static const mode_t CHOWN_RW_USR_GRP = 0600;
32 static const int32_t LOG_FREQUENCY = 10;
33 std::unordered_map<uint32_t, std::shared_ptr<VideoEditor>> VideoCompositionCallbackImpl::editorMap_;
34 std::queue<VideoCompositionCallbackImpl::Task> VideoCompositionCallbackImpl::waitQueue_;
35 int32_t VideoCompositionCallbackImpl::curWorkerNum_ = 0;
36 std::mutex VideoCompositionCallbackImpl::mutex_;
37 
CheckDirPathReal(const std::string & filePath)38 static int32_t CheckDirPathReal(const std::string &filePath)
39 {
40     string dirPath;
41     auto index = filePath.rfind('/');
42     CHECK_AND_RETURN_RET_LOG(index != std::string::npos, E_HAS_FS_ERROR,
43         "find split for last string failed, %{private}s, errno: %{public}d", filePath.c_str(), errno);
44     dirPath = filePath.substr(0, index);
45     string absDirPath;
46     CHECK_AND_RETURN_RET_LOG(PathToRealPath(dirPath, absDirPath),
47         E_HAS_FS_ERROR, "file is not real path: %{private}s, errno: %{public}d", dirPath.c_str(), errno);
48     return E_OK;
49 }
50 
VideoCompositionCallbackImpl()51 VideoCompositionCallbackImpl::VideoCompositionCallbackImpl() {}
52 
onResult(VEFResult result,VEFError errorCode)53 void VideoCompositionCallbackImpl::onResult(VEFResult result, VEFError errorCode)
54 {
55     close(inputFileFd_);
56     close(outputFileFd_);
57     editorMap_.erase(inputFileFd_);
58     size_t lastSlash = videoPath_.rfind('.');
59     string sourceImagePath = videoPath_.substr(0, lastSlash) + ".jpg";
60     string sourceVideoPath = MediaFileUtils::GetMovingPhotoVideoPath(sourceImagePath);
61     if (errorCode != VEFError::ERR_OK) {
62         mutex_.lock();
63         --curWorkerNum_;
64         mutex_.unlock();
65         MEDIA_ERR_LOG("VideoCompositionCallbackImpl onResult error:%{public}d", (int32_t)errorCode);
66         // Video Composite failed save sourceVideo to photo directory
67         CHECK_AND_RETURN_LOG(MediaFileUtils::CopyFileUtil(sourceVideoPath, videoPath_),
68             "Copy sourceVideoPath to videoPath, path:%{private}s", sourceVideoPath.c_str());
69         return;
70     }
71 
72     mutex_.lock();
73     if (waitQueue_.empty()) {
74         --curWorkerNum_;
75         mutex_.unlock();
76     } else {
77         Task task = std::move(waitQueue_.front());
78         waitQueue_.pop();
79         mutex_.unlock();
80         if (CallStartComposite(task.sourceVideoPath_, task.videoPath_, task.editData_) != E_OK) {
81             mutex_.lock();
82             --curWorkerNum_;
83             mutex_.unlock();
84             MEDIA_ERR_LOG("Failed to CallStartComposite, path:%{private}s", task.videoPath_.c_str());
85             CHECK_AND_RETURN_LOG(MediaFileUtils::CopyFileUtil(task.sourceVideoPath_, task.videoPath_),
86                 "Copy sourceVideoPath to videoPath, path:%{private}s", task.sourceVideoPath_.c_str());
87         }
88     }
89 }
90 
onProgress(uint32_t progress)91 void VideoCompositionCallbackImpl::onProgress(uint32_t progress)
92 {
93     if (!(progress % LOG_FREQUENCY)) {
94         MEDIA_INFO_LOG("VideoCompositionCallbackImpl onProcess:%{public}d, tempPath:%{public}s",
95             (int32_t)progress, videoPath_.c_str());
96     }
97 }
98 
CallStartComposite(const std::string & sourceVideoPath,const std::string & videoPath,const std::string & effectDescription)99 int32_t VideoCompositionCallbackImpl::CallStartComposite(const std::string& sourceVideoPath,
100     const std::string& videoPath, const std::string& effectDescription)
101 {
102     MEDIA_INFO_LOG("Call StartComposite begin, sourceVideoPath:%{public}s", sourceVideoPath.c_str());
103     string absSourceVideoPath;
104     CHECK_AND_RETURN_RET_LOG(PathToRealPath(sourceVideoPath, absSourceVideoPath), E_HAS_FS_ERROR,
105         "file is not real path, file path: %{private}s, errno: %{public}d", sourceVideoPath.c_str(), errno);
106     int32_t inputFileFd = open(absSourceVideoPath.c_str(), O_RDONLY);
107     CHECK_AND_RETURN_RET_LOG(inputFileFd != -1, E_ERR, "Open failed for inputFileFd file, errno: %{public}d", errno);
108 
109     if (CheckDirPathReal(videoPath) != E_OK) {
110         MEDIA_ERR_LOG("dirFile is not real path, file path: %{private}s, errno: %{public}d",
111             videoPath.c_str(), errno);
112         close(inputFileFd);
113         return E_HAS_FS_ERROR;
114     }
115     int32_t outputFileFd = open(videoPath.c_str(), O_WRONLY|O_CREAT, CHOWN_RW_USR_GRP);
116     if (outputFileFd == -1) {
117         close(inputFileFd);
118         MEDIA_ERR_LOG("Open failed for outputFileFd file, errno: %{public}d", errno);
119         return E_ERR;
120     }
121 
122     auto callBack = std::make_shared<VideoCompositionCallbackImpl>();
123     auto editor = VideoEditorFactory::CreateVideoEditor();
124     if (editor == nullptr) {
125         close(inputFileFd);
126         close(outputFileFd);
127         MEDIA_ERR_LOG("CreateEditor failed with error");
128         return E_ERR;
129     }
130     callBack->inputFileFd_ = inputFileFd;
131     callBack->outputFileFd_ = outputFileFd;
132     callBack->videoPath_ = videoPath;
133 
134     VEFError error = editor->AppendVideoFile(inputFileFd, effectDescription);
135     if (error != VEFError::ERR_OK) {
136         close(inputFileFd);
137         close(outputFileFd);
138         editor = nullptr;
139         MEDIA_ERR_LOG("AppendVideoFile failed with error: %{public}d", (int32_t)error);
140         return E_ERR;
141     }
142     auto compositionOptions = std::make_shared<CompositionOptions>(outputFileFd, callBack);
143     error = editor->StartComposite(compositionOptions);
144     if (error != VEFError::ERR_OK) {
145         close(inputFileFd);
146         close(outputFileFd);
147         editor = nullptr;
148         MEDIA_ERR_LOG("StartComposite failed with error: %{public}d", (int32_t)error);
149         return E_ERR;
150     }
151     callBack->editorMap_[inputFileFd] = editor;
152     return E_OK;
153 }
154 
AddCompositionTask(std::string & assetPath,std::string & editData)155 void VideoCompositionCallbackImpl::AddCompositionTask(std::string& assetPath, std::string& editData)
156 {
157     string sourceImagePath = PhotoFileUtils::GetEditDataSourcePath(assetPath);
158     string videoPath = MediaFileUtils::GetMovingPhotoVideoPath(assetPath);
159     string sourceVideoPath = MediaFileUtils::GetMovingPhotoVideoPath(sourceImagePath);
160 
161     mutex_.lock();
162     if (curWorkerNum_ < MAX_CONCURRENT_NUM) {
163         ++curWorkerNum_;
164         mutex_.unlock();
165         if (CallStartComposite(sourceVideoPath, videoPath, editData) != E_OK) {
166             mutex_.lock();
167             --curWorkerNum_;
168             mutex_.unlock();
169             MEDIA_ERR_LOG("Failed to CallStartComposite, path:%{private}s", videoPath.c_str());
170             CHECK_AND_RETURN_LOG(MediaFileUtils::CopyFileUtil(sourceVideoPath, videoPath),
171                 "Copy sourceVideoPath to videoPath, path:%{private}s", sourceVideoPath.c_str());
172         }
173     } else {
174         MEDIA_WARN_LOG("Failed to CallStartComposite, curWorkerNum over MAX_CONCURRENT_NUM");
175         Task newWaitTask{sourceVideoPath, videoPath, editData};
176         waitQueue_.push(std::move(newWaitTask));
177         mutex_.unlock();
178     }
179 }
180 
EraseStickerField(std::string & editData,size_t index,bool isTimingSticker)181 void VideoCompositionCallbackImpl::EraseStickerField(std::string& editData, size_t index, bool isTimingSticker)
182 {
183     auto begin = index - START_DISTANCE;
184     auto end = index;
185     while (editData[end] != '}') {
186         ++end;
187     }
188     if (!isTimingSticker) {
189         ++end;
190     }
191     auto len = end - begin + 1;
192     editData.erase(begin, len);
193 }
194 
195 } // end of namespace
196 }