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 <cstdlib>
17 #include <iomanip>
18 #include <map>
19 #include <string>
20 #include <variant>
21 #include <vector>
22 #include "ffi_remote_data.h"
23 #include "securec.h"
24
25 #include "camera_error.h"
26 #include "camera_log.h"
27 #include "camera_manager.h"
28 #include "surface_utils.h"
29 #include "video_output_impl.h"
30
31 using namespace OHOS::FFI;
32
33 namespace OHOS::CameraStandard {
34 thread_local sptr<VideoOutput> CJVideoOutput::sVideoOutput_ = nullptr;
35
OnFrameStarted() const36 void CJVideoCallbackListener::OnFrameStarted() const
37 {
38 std::lock_guard<std::mutex> lock(frameStartedMutex);
39 if (frameStartedCallbackList.size() == 0) {
40 return;
41 }
42 for (size_t i = 0; i < frameStartedCallbackList.size(); i++) {
43 if (frameStartedCallbackList[i] != nullptr) {
44 frameStartedCallbackList[i]->ref();
45 }
46 }
47 }
48
OnFrameEnded(const int32_t frameCount) const49 void CJVideoCallbackListener::OnFrameEnded(const int32_t frameCount) const
50 {
51 std::lock_guard<std::mutex> lock(frameEndedMutex);
52 if (frameEndedCallbackList.size() == 0) {
53 return;
54 }
55 for (size_t i = 0; i < frameEndedCallbackList.size(); i++) {
56 if (frameEndedCallbackList[i] != nullptr) {
57 frameEndedCallbackList[i]->ref();
58 }
59 }
60 }
61
OnError(const int32_t errorCode) const62 void CJVideoCallbackListener::OnError(const int32_t errorCode) const
63 {
64 std::lock_guard<std::mutex> lock(errorMutex);
65 if (errorCallbackList.size() == 0) {
66 return;
67 }
68 for (size_t i = 0; i < errorCallbackList.size(); i++) {
69 if (errorCallbackList[i] != nullptr) {
70 errorCallbackList[i]->ref(errorCode);
71 }
72 }
73 }
74
OnDeferredVideoEnhancementInfo(const CaptureEndedInfoExt info) const75 void CJVideoCallbackListener::OnDeferredVideoEnhancementInfo(const CaptureEndedInfoExt info) const
76 {
77 }
78
CJVideoOutput()79 CJVideoOutput::CJVideoOutput()
80 {
81 videoOutput_ = sVideoOutput_;
82 sVideoOutput_ = nullptr;
83 }
84
GetCameraOutput()85 sptr<CameraStandard::CaptureOutput> CJVideoOutput::GetCameraOutput()
86 {
87 return videoOutput_;
88 }
89
Release()90 int32_t CJVideoOutput::Release()
91 {
92 if (videoOutput_ == nullptr) {
93 return CameraError::CAMERA_SERVICE_ERROR;
94 }
95 return videoOutput_->Release();
96 }
97
CreateVideoOutput(VideoProfile & profile,std::string surfaceId)98 int32_t CJVideoOutput::CreateVideoOutput(VideoProfile &profile, std::string surfaceId)
99 {
100 uint64_t iSurfaceId;
101 std::istringstream iss(surfaceId);
102 iss >> iSurfaceId;
103 sptr<Surface> surface = SurfaceUtils::GetInstance()->GetSurface(iSurfaceId);
104 if (surface == nullptr) {
105 MEDIA_ERR_LOG("failed to get surface from SurfaceUtils");
106 return CameraError::CAMERA_SERVICE_ERROR;
107 }
108 surface->SetUserData(CameraManager::surfaceFormat, std::to_string(profile.GetCameraFormat()));
109 int retCode = CameraManager::GetInstance()->CreateVideoOutput(profile, surface, &sVideoOutput_);
110 if (sVideoOutput_ == nullptr) {
111 MEDIA_ERR_LOG("failed to create VideoOutput");
112 return CameraError::CAMERA_SERVICE_ERROR;
113 }
114 return retCode;
115 }
116
CreateVideoOutputWithOutProfile(std::string surfaceId)117 int32_t CJVideoOutput::CreateVideoOutputWithOutProfile(std::string surfaceId)
118 {
119 uint64_t iSurfaceId;
120 std::istringstream iss(surfaceId);
121 iss >> iSurfaceId;
122 sptr<Surface> surface = SurfaceUtils::GetInstance()->GetSurface(iSurfaceId);
123 if (surface == nullptr) {
124 MEDIA_ERR_LOG("failed to get surface from SurfaceUtils");
125 return CameraError::CAMERA_SERVICE_ERROR;
126 }
127 int retCode = CameraManager::GetInstance()->CreateVideoOutputWithoutProfile(surface, &sVideoOutput_);
128 if (sVideoOutput_ == nullptr) {
129 MEDIA_ERR_LOG("failed to create VideoOutput");
130 return CameraError::CAMERA_SERVICE_ERROR;
131 }
132 return retCode;
133 }
134
Start()135 int32_t CJVideoOutput::Start()
136 {
137 if (videoOutput_ == nullptr) {
138 return CameraError::CAMERA_SERVICE_ERROR;
139 }
140 return videoOutput_->Start();
141 }
142
Stop()143 int32_t CJVideoOutput::Stop()
144 {
145 if (videoOutput_ == nullptr) {
146 return CameraError::CAMERA_SERVICE_ERROR;
147 }
148 return videoOutput_->Stop();
149 }
150
GetSupportedFrameRates(int32_t * errCode)151 CArrFrameRateRange CJVideoOutput::GetSupportedFrameRates(int32_t *errCode)
152 {
153 MEDIA_INFO_LOG("GetSupportedFrameRates is called!");
154 CArrFrameRateRange cArrFrameRateRange = CArrFrameRateRange{0};
155 if (videoOutput_ == nullptr) {
156 MEDIA_ERR_LOG("videoOutput is nullptr.");
157 *errCode = CameraError::CAMERA_SERVICE_ERROR;
158 return cArrFrameRateRange;
159 }
160 std::vector<std::vector<int32_t>> supportedFrameRatesRange = videoOutput_->GetSupportedFrameRates();
161 MEDIA_INFO_LOG("CJVideoOutput::GetSupportedFrameRates len = %{public}zu", supportedFrameRatesRange.size());
162 if (supportedFrameRatesRange.size() > 0) {
163 FrameRateRange *retArrFrameRateRange =
164 (FrameRateRange *)malloc(sizeof(FrameRateRange) * supportedFrameRatesRange.size());
165 if (retArrFrameRateRange == nullptr) {
166 *errCode = CameraError::CAMERA_SERVICE_ERROR;
167 return cArrFrameRateRange;
168 }
169 for (size_t i = 0; i < supportedFrameRatesRange.size(); i++) {
170 retArrFrameRateRange[i].min = supportedFrameRatesRange[i][0];
171 retArrFrameRateRange[i].max = supportedFrameRatesRange[i][1];
172 }
173 cArrFrameRateRange.head = retArrFrameRateRange;
174 cArrFrameRateRange.size = static_cast<int64_t>(supportedFrameRatesRange.size());
175 } else {
176 MEDIA_ERR_LOG("cArrFrameRateRange is empty!");
177 }
178 return cArrFrameRateRange;
179 }
180
SetFrameRate(int32_t minFps,int32_t maxFps)181 int32_t CJVideoOutput::SetFrameRate(int32_t minFps, int32_t maxFps)
182 {
183 MEDIA_INFO_LOG("SetFrameRate is called");
184 if (videoOutput_ == nullptr) {
185 MEDIA_ERR_LOG("videoOutput is nullptr.");
186 return CameraError::CAMERA_SERVICE_ERROR;
187 }
188 return videoOutput_->SetFrameRate(minFps, maxFps);
189 }
190
GetActiveFrameRate(int32_t * errCode)191 FrameRateRange CJVideoOutput::GetActiveFrameRate(int32_t *errCode)
192 {
193 MEDIA_INFO_LOG("GetActiveFrameRate is called");
194 FrameRateRange frameRateRange = FrameRateRange{0};
195 if (videoOutput_ == nullptr) {
196 MEDIA_ERR_LOG("videoOutput is nullptr.");
197 *errCode = CameraError::CAMERA_SERVICE_ERROR;
198 return frameRateRange;
199 }
200 std::vector<int32_t> fRateRange = videoOutput_->GetFrameRateRange();
201 frameRateRange.min = fRateRange[0];
202 frameRateRange.max = fRateRange[1];
203 return frameRateRange;
204 }
205
GetActiveProfile(int32_t * errCode)206 CJVideoProfile CJVideoOutput::GetActiveProfile(int32_t *errCode)
207 {
208 MEDIA_DEBUG_LOG("VideoOutputNapi::GetActiveProfile is called");
209 CJVideoProfile cjVideoProfile = CJVideoProfile{0};
210 if (videoOutput_ == nullptr) {
211 MEDIA_ERR_LOG("videoOutput is nullptr.");
212 *errCode = CameraError::CAMERA_SERVICE_ERROR;
213 return cjVideoProfile;
214 }
215 auto profile = videoOutput_->GetVideoProfile();
216 if (profile == nullptr) {
217 *errCode = CameraError::CAMERA_SERVICE_ERROR;
218 return cjVideoProfile;
219 }
220 cjVideoProfile.format = profile->GetCameraFormat();
221 Size size = profile->GetSize();
222 cjVideoProfile.width = size.width;
223 cjVideoProfile.height = size.height;
224 std::vector<int32_t> vpi_framerates = profile->GetFrameRates();
225 cjVideoProfile.frameRateRange.min = vpi_framerates[0];
226 cjVideoProfile.frameRateRange.max = vpi_framerates[1];
227 return cjVideoProfile;
228 }
229
GetVideoRotation(int32_t imageRotation,int32_t * errCode)230 int32_t CJVideoOutput::GetVideoRotation(int32_t imageRotation, int32_t *errCode)
231 {
232 MEDIA_DEBUG_LOG("GetVideoRotation is called!");
233 if (videoOutput_ == nullptr) {
234 MEDIA_ERR_LOG("videoOutput is nullptr.");
235 *errCode = CameraError::CAMERA_SERVICE_ERROR;
236 return -1;
237 }
238 int32_t retCode = videoOutput_->GetVideoRotation(imageRotation);
239 if (retCode == CameraError::CAMERA_SERVICE_ERROR) {
240 *errCode = CameraError::CAMERA_SERVICE_ERROR;
241 return -1;
242 }
243 return retCode;
244 }
245
OnFrameStart(int64_t callbackId)246 void CJVideoOutput::OnFrameStart(int64_t callbackId)
247 {
248 if (videoCallback_ == nullptr) {
249 videoCallback_ = std::make_shared<CJVideoCallbackListener>();
250 if (videoCallback_ == nullptr || videoOutput_ == nullptr) {
251 return;
252 }
253 videoOutput_->SetCallback(videoCallback_);
254 }
255 auto cFunc = reinterpret_cast<void (*)()>(callbackId);
256 auto callback = [lambda = CJLambda::Create(cFunc)]() -> void { lambda(); };
257 auto callbackRef = std::make_shared<CallbackRef<>>(callback, callbackId);
258
259 std::lock_guard<std::mutex> lock(videoCallback_->frameStartedMutex);
260 videoCallback_->frameStartedCallbackList.push_back(callbackRef);
261 }
262
OffFrameStart(int64_t callbackId)263 void CJVideoOutput::OffFrameStart(int64_t callbackId)
264 {
265 if (videoCallback_ == nullptr) {
266 return;
267 }
268 std::lock_guard<std::mutex> lock(videoCallback_->frameStartedMutex);
269 for (auto it = videoCallback_->frameStartedCallbackList.begin();
270 it != videoCallback_->frameStartedCallbackList.end(); it++) {
271 if ((*it)->id == callbackId) {
272 videoCallback_->frameStartedCallbackList.erase(it);
273 break;
274 }
275 }
276 }
277
OffAllFrameStart()278 void CJVideoOutput::OffAllFrameStart()
279 {
280 if (videoCallback_ == nullptr) {
281 return;
282 }
283 std::lock_guard<std::mutex> lock(videoCallback_->frameStartedMutex);
284 videoCallback_->frameStartedCallbackList.clear();
285 }
286
OnFrameEnd(int64_t callbackId)287 void CJVideoOutput::OnFrameEnd(int64_t callbackId)
288 {
289 if (videoCallback_ == nullptr) {
290 videoCallback_ = std::make_shared<CJVideoCallbackListener>();
291 if (videoCallback_ == nullptr || videoOutput_ == nullptr) {
292 return;
293 }
294 videoOutput_->SetCallback(videoCallback_);
295 }
296 auto cFunc = reinterpret_cast<void (*)()>(callbackId);
297 auto callback = [lambda = CJLambda::Create(cFunc)]() -> void { lambda(); };
298 auto callbackRef = std::make_shared<CallbackRef<>>(callback, callbackId);
299
300 std::lock_guard<std::mutex> lock(videoCallback_->frameEndedMutex);
301 videoCallback_->frameEndedCallbackList.push_back(callbackRef);
302 }
303
OffFrameEnd(int64_t callbackId)304 void CJVideoOutput::OffFrameEnd(int64_t callbackId)
305 {
306 if (videoCallback_ == nullptr) {
307 return;
308 }
309 std::lock_guard<std::mutex> lock(videoCallback_->frameEndedMutex);
310 for (auto it = videoCallback_->frameEndedCallbackList.begin();
311 it != videoCallback_->frameEndedCallbackList.end(); it++) {
312 if ((*it)->id == callbackId) {
313 videoCallback_->frameEndedCallbackList.erase(it);
314 break;
315 }
316 }
317 }
318
OffAllFrameEnd()319 void CJVideoOutput::OffAllFrameEnd()
320 {
321 if (videoCallback_ == nullptr) {
322 return;
323 }
324 std::lock_guard<std::mutex> lock(videoCallback_->frameEndedMutex);
325 videoCallback_->frameEndedCallbackList.clear();
326 }
327
OnError(int64_t callbackId)328 void CJVideoOutput::OnError(int64_t callbackId)
329 {
330 if (videoCallback_ == nullptr) {
331 videoCallback_ = std::make_shared<CJVideoCallbackListener>();
332 if (videoCallback_ == nullptr || videoOutput_ == nullptr) {
333 return;
334 }
335 videoOutput_->SetCallback(videoCallback_);
336 }
337 auto cFunc = reinterpret_cast<void (*)(const int32_t errorCode)>(callbackId);
338 auto callback = [lambda = CJLambda::Create(cFunc)](const int32_t errorCode) -> void { lambda(errorCode); };
339 auto callbackRef = std::make_shared<CallbackRef<const int32_t>>(callback, callbackId);
340
341 std::lock_guard<std::mutex> lock(videoCallback_->errorMutex);
342 videoCallback_->errorCallbackList.push_back(callbackRef);
343 }
344
OffError(int64_t callbackId)345 void CJVideoOutput::OffError(int64_t callbackId)
346 {
347 if (videoCallback_ == nullptr) {
348 return;
349 }
350 std::lock_guard<std::mutex> lock(videoCallback_->errorMutex);
351 for (auto it = videoCallback_->errorCallbackList.begin(); it != videoCallback_->errorCallbackList.end(); it++) {
352 if ((*it)->id == callbackId) {
353 videoCallback_->errorCallbackList.erase(it);
354 break;
355 }
356 }
357 }
358
OffAllError()359 void CJVideoOutput::OffAllError()
360 {
361 if (videoCallback_ == nullptr) {
362 return;
363 }
364 std::lock_guard<std::mutex> lock(videoCallback_->errorMutex);
365 videoCallback_->errorCallbackList.clear();
366 }
367
368 } // namespace OHOS::CameraStandard