1 /*
2 * Copyright (C) 2025 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 "MediaCallTranscode"
17 #include "moving_photo_call_transcoder.h"
18
19 #include "js_native_api_types.h"
20 #include "medialibrary_errno.h"
21 #include "medialibrary_napi_log.h"
22 #include "moving_photo_transcoder_observer.h"
23 #include "native_event.h"
24 #include "unique_fd.h"
25
26 namespace OHOS {
27 namespace Media {
28 const char* ON_PROGRESS_FUNC = "onProgress";
DoTranscode(const std::shared_ptr<MovingPhotoProgressHandler> & movingPhotoProgressHandler)29 bool MovingPhotoCallTranscoder::DoTranscode(const std::shared_ptr<MovingPhotoProgressHandler>
30 &movingPhotoProgressHandler)
31 {
32 if (movingPhotoProgressHandler == nullptr) {
33 NAPI_ERR_LOG("movingPhotoProgressHandler is null");
34 return false;
35 }
36 auto transCoder = TransCoderFactory::CreateTransCoder();
37 if (transCoder == nullptr) {
38 NAPI_ERR_LOG("Failed to create TransCoder");
39 return false;
40 }
41 auto transCoderCb = std::make_shared<OHOS::Media::MovingphotoTranscoderObserver>();
42 if (transCoderCb == nullptr) {
43 NAPI_ERR_LOG("Failed to create transCoderCb");
44 return false;
45 }
46 transCoderCb->SetMovingPhotoProgress(movingPhotoProgressHandler);
47 transCoderCb->setTransCoder(transCoder);
48 if (transCoder->SetTransCoderCallback(transCoderCb) != E_OK) {
49 return transCoderCb->DoTranscodePrepareError("Failed to set TransCoder callback");
50 }
51 if (transCoder->SetInputFile(movingPhotoProgressHandler->srcFd.Get(), movingPhotoProgressHandler->offset,
52 movingPhotoProgressHandler->size) != E_OK) {
53 return transCoderCb->DoTranscodePrepareError("Failed to set input file for TransCoder");
54 }
55 if (transCoder->SetOutputFile(movingPhotoProgressHandler->destFd.Get()) != E_OK) {
56 return transCoderCb->DoTranscodePrepareError("Failed to set output file for TransCoder");
57 }
58 if (transCoder->SetOutputFormat(FORMAT_MPEG_4) != E_OK) {
59 return transCoderCb->DoTranscodePrepareError("Failed to SetOutputFormat");
60 }
61 if (transCoder->SetColorSpace(TRANSCODER_COLORSPACE_P3_FULL) != E_OK) {
62 return transCoderCb->DoTranscodePrepareError("Failed to SetColorSpace");
63 }
64 if (transCoder->Prepare() != E_OK) {
65 return transCoderCb->DoTranscodePrepareError("Failed to prepare TransCoder");
66 }
67 if (transCoder->Start() != E_OK) {
68 return transCoderCb->DoTranscodePrepareError("Failed to TransCoder Start");
69 }
70 NAPI_INFO_LOG("DoTranscode success");
71 return true;
72 }
73
DoTranscodePrepareError(const std::string & errorMsg)74 bool MovingphotoTranscoderObserver::DoTranscodePrepareError(const std::string &errorMsg)
75 {
76 NAPI_ERR_LOG("DoTranscodePrepareError errorMsg:%{public}s", errorMsg.c_str());
77 isPrepareError.store(true);
78 if (transCoder_ != nullptr) {
79 transCoder_->Release();
80 }
81 return false;
82 }
83
CallMovingProgressCallback(bool isComplete)84 void MovingphotoTranscoderObserver::CallMovingProgressCallback(bool isComplete)
85 {
86 NAPI_DEBUG_LOG("CallMovingProgressCallback");
87 if (movingPhotoProgressHandler_ == nullptr || movingPhotoProgressHandler_->onProgressFunc == nullptr) {
88 NAPI_ERR_LOG("CallMovingProgressCallback: movingPhotoProgressHandler_ is null");
89 return;
90 }
91
92 napi_status status = napi_acquire_threadsafe_function(movingPhotoProgressHandler_->onProgressFunc);
93 if (status != napi_ok) {
94 NAPI_ERR_LOG("napi_acquire_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
95 return;
96 }
97 auto asyncHandler = std::make_unique<MovingPhotoProgressHandler>();
98 if (asyncHandler == nullptr) {
99 NAPI_ERR_LOG("CallMovingProgressCallback: asyncHandler is null");
100 return;
101 }
102 asyncHandler->isComplete = isComplete;
103 if (isComplete) {
104 asyncHandler->env = movingPhotoProgressHandler_->env;
105 asyncHandler->contextData = movingPhotoProgressHandler_->contextData;
106 asyncHandler->errCode = movingPhotoProgressHandler_->errCode;
107 asyncHandler->callbackFunc = movingPhotoProgressHandler_->callbackFunc;
108 } else {
109 asyncHandler->mediaAssetEnv = movingPhotoProgressHandler_->mediaAssetEnv;
110 asyncHandler->extra = movingPhotoProgressHandler_->extra;
111 asyncHandler->progressHandlerRef = movingPhotoProgressHandler_->progressHandlerRef;
112 }
113
114 status = napi_call_threadsafe_function(movingPhotoProgressHandler_->onProgressFunc, (void *)asyncHandler.get(),
115 napi_tsfn_blocking);
116 if (status != napi_ok) {
117 NAPI_ERR_LOG("napi_call_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
118 }
119 (void)asyncHandler.release();
120 }
121
OnProgress(napi_env env,napi_value cb,void * context,void * data)122 void MovingPhotoCallTranscoder::OnProgress(napi_env env, napi_value cb, void *context, void *data)
123 {
124 NAPI_DEBUG_LOG("OnProgress");
125 auto mpHandler = reinterpret_cast<MovingPhotoProgressHandler *>(data);
126 if (mpHandler == nullptr) {
127 NAPI_ERR_LOG("Moving photo progress env is null");
128 return;
129 }
130 if (mpHandler->isComplete) {
131 if (mpHandler->callbackFunc == nullptr) {
132 NAPI_ERR_LOG("OnProgress callbackFunc is null");
133 return;
134 }
135 mpHandler->callbackFunc(mpHandler->env, mpHandler->contextData, mpHandler->errCode);
136 return;
137 }
138 if (mpHandler->mediaAssetEnv == nullptr) {
139 NAPI_ERR_LOG("mpHandler mediaAssetEnv is null");
140 return;
141 }
142 napi_value result;
143 napi_status status = napi_create_int32(mpHandler->mediaAssetEnv,
144 mpHandler->extra, &result);
145 if (status != napi_ok) {
146 NAPI_ERR_LOG("OnProgress napi_create_int32 fail");
147 return;
148 }
149 napi_value jsCallback = nullptr;
150 status = napi_get_reference_value(mpHandler->mediaAssetEnv,
151 mpHandler->progressHandlerRef, &jsCallback);
152 if (status != napi_ok) {
153 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
154 return;
155 }
156 napi_value jsOnProgress;
157 status = napi_get_named_property(mpHandler->mediaAssetEnv, jsCallback, ON_PROGRESS_FUNC,
158 &jsOnProgress);
159 if (status != napi_ok) {
160 NAPI_ERR_LOG("jsOnProgress napi_get_named_property fail, napi status: %{public}d",
161 static_cast<int>(status));
162 return;
163 }
164 const size_t ARGS_ONE = 1;
165 napi_value argv[ARGS_ONE];
166 napi_value retVal = nullptr;
167 argv[0] = result;
168 napi_call_function(mpHandler->mediaAssetEnv, nullptr, jsOnProgress, ARGS_ONE, argv, &retVal);
169 if (status != napi_ok) {
170 NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", static_cast<int>(status));
171 }
172 }
173
SetMovingPhotoProgress(const std::shared_ptr<MovingPhotoProgressHandler> & movingPhotoProgressHandler)174 void MovingphotoTranscoderObserver::SetMovingPhotoProgress(
175 const std::shared_ptr<MovingPhotoProgressHandler> &movingPhotoProgressHandler)
176 {
177 movingPhotoProgressHandler_ = movingPhotoProgressHandler;
178 }
179
OnInfo(int32_t type,int32_t extra)180 void MovingphotoTranscoderObserver::OnInfo(int32_t type, int32_t extra)
181 {
182 NAPI_INFO_LOG("MediaAssetManagerCallback OnInfo type:%{public}d extra:%{public}d", type, extra);
183 if (movingPhotoProgressHandler_ == nullptr) {
184 NAPI_ERR_LOG("OnInfo, movingPhotoProgressHandler_ is null");
185 return;
186 }
187 if (type == INFO_TYPE_TRANSCODER_COMPLETED) {
188 if (transCoder_ == nullptr) {
189 NAPI_ERR_LOG("transCoder_ is null, cannot release resources");
190 return;
191 }
192 movingPhotoProgressHandler_->errCode = E_OK;
193 CallMovingProgressCallback(true);
194 transCoder_->Release();
195 return;
196 }
197 if (movingPhotoProgressHandler_->progressHandlerRef == nullptr) {
198 NAPI_INFO_LOG("progressHandlerRef is nullptr");
199 return;
200 }
201 movingPhotoProgressHandler_->extra = extra;
202 CallMovingProgressCallback();
203 }
204
OnError(int32_t errCode,const std::string & errorMsg)205 void MovingphotoTranscoderObserver::OnError(int32_t errCode, const std::string &errorMsg)
206 {
207 NAPI_ERR_LOG("MediaAssetManagerCallback OnError errCode:%{public}d errorMsg:%{public}s",
208 errCode, errorMsg.c_str());
209 if (transCoder_ != nullptr) {
210 transCoder_->Release();
211 }
212 if (isPrepareError.load()) {
213 return;
214 }
215 if (movingPhotoProgressHandler_ != nullptr) {
216 movingPhotoProgressHandler_->errCode = E_ERR;
217 }
218 CallMovingProgressCallback(true);
219 }
220 } // namespace Media
221 } // namespace OHOS
222