1 /*
2  * Copyright (c) 2021-2022 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 <unistd.h>
17 #include "input/camera_input.h"
18 #include "input/camera_manager.h"
19 #include "media_errors.h"
20 #include "camera_log.h"
21 #include "recorder.h"
22 #include "surface.h"
23 #include "test_common.h"
24 
25 #include "ipc_skeleton.h"
26 #include "access_token.h"
27 #include "hap_token_info.h"
28 #include "accesstoken_kit.h"
29 #include "nativetoken_kit.h"
30 #include "token_setproc.h"
31 
32 using namespace std;
33 using namespace OHOS;
34 using namespace OHOS::CameraStandard;
35 using namespace OHOS::Media;
36 
37 namespace {
38     int32_t g_videoFd = -1;
39     class TestVideoRecorderCallback : public RecorderCallback {
40     public:
OnError(RecorderErrorType errorType, int32_t errorCode)41         void OnError(RecorderErrorType errorType, int32_t errorCode)
42         {
43             MEDIA_DEBUG_LOG("OnError errorType is %{public}d, errorCode is  %{public}d", errorType, errorCode);
44         }
OnInfo(int32_t type, int32_t extra)45         void OnInfo(int32_t type, int32_t extra)
46         {
47             MEDIA_DEBUG_LOG("OnInfo Type is %{public}d, extra is  %{public}d", type, extra);
48         }
OnAudioCaptureChange(const AudioRecorderChangeInfo &audioRecorderChangeInfo)49         void OnAudioCaptureChange(const AudioRecorderChangeInfo &audioRecorderChangeInfo)
50         {
51             MEDIA_DEBUG_LOG("OnAudioCaptureChange");
52         }
53     };
54 
ConfigureVideoParams(const std::shared_ptr<Recorder> &recorder, int32_t videoSourceId, int32_t width, int32_t height)55     bool ConfigureVideoParams(const std::shared_ptr<Recorder> &recorder,
56                               int32_t videoSourceId, int32_t width, int32_t height)
57     {
58         int32_t encodingBitRate  = 48000;
59         int32_t frameRate = 30;
60         int32_t captureRate = 30;
61 
62         if (recorder->SetVideoEncoder(videoSourceId, Media::H264)) {
63             MEDIA_DEBUG_LOG("Set Video Encoder Failed");
64             return false;
65         }
66 
67         if (recorder->SetVideoSize(videoSourceId, width, height)) {
68             MEDIA_DEBUG_LOG("Set Video Size Failed");
69             return false;
70         }
71 
72         if (recorder->SetVideoFrameRate(videoSourceId, frameRate)) {
73             MEDIA_DEBUG_LOG("Set Video Frame Rate Failed");
74             return false;
75         }
76 
77         if (recorder->SetVideoEncodingBitRate(videoSourceId, encodingBitRate)) {
78             MEDIA_DEBUG_LOG("Set Video Encoding Bit Rate Failed");
79             return false;
80         }
81 
82         if (recorder->SetCaptureRate(videoSourceId, captureRate)) {
83             MEDIA_DEBUG_LOG("Set Capture Rate Failed");
84             return false;
85         }
86 
87         return true;
88     }
89 
ConfigureAudioParams(const std::shared_ptr<Recorder> &recorder, int32_t audioSourceId)90     bool ConfigureAudioParams(const std::shared_ptr<Recorder> &recorder, int32_t audioSourceId)
91     {
92         int32_t channelCount = 2;
93         int32_t sampleRate = 48000;
94         int32_t encodingBitRate = 48000;
95 
96         if (recorder->SetAudioEncoder(audioSourceId, Media::AAC_LC)) {
97             MEDIA_DEBUG_LOG("Set Audio Encoder Failed");
98             return false;
99         }
100 
101         if (recorder->SetAudioSampleRate(audioSourceId, sampleRate)) {
102             MEDIA_DEBUG_LOG("Set Audio Sample Rate Failed");
103             return false;
104         }
105 
106         if (recorder->SetAudioChannels(audioSourceId, channelCount)) {
107             MEDIA_DEBUG_LOG("Set Audio Channels Failed");
108             return false;
109         }
110 
111         if (recorder->SetAudioEncodingBitRate(audioSourceId, encodingBitRate)) {
112             MEDIA_DEBUG_LOG("Set Audio Encoding Bit Rate Failed");
113             return false;
114         }
115 
116         return true;
117     }
118 
CreateAndConfigureRecorder(std::shared_ptr<Recorder> &recorder, int32_t &videoSourceId, int32_t width, int32_t height)119     bool CreateAndConfigureRecorder(std::shared_ptr<Recorder> &recorder,
120                                     int32_t &videoSourceId, int32_t width, int32_t height)
121     {
122         int32_t maxDuration = 36000;
123 
124         recorder = RecorderFactory::CreateRecorder();
125         if (recorder == nullptr) {
126             MEDIA_DEBUG_LOG("Create Recorder Failed");
127             return false;
128         }
129 
130         int32_t audioSourceId = 0;
131         if (recorder->SetVideoSource(Media::VIDEO_SOURCE_SURFACE_ES, videoSourceId)) {
132             MEDIA_DEBUG_LOG("Set Video Source Failed");
133             return false;
134         }
135 
136         if (recorder->SetAudioSource(Media::AUDIO_MIC, audioSourceId)) {
137             MEDIA_DEBUG_LOG("Set Audio Source Failed");
138             return false;
139         }
140 
141         if (recorder->SetOutputFormat(Media::FORMAT_MPEG_4)) {
142             MEDIA_DEBUG_LOG("Set Output Format Failed");
143             return false;
144         }
145 
146         if (!ConfigureVideoParams(recorder, videoSourceId, width, height)) {
147             MEDIA_DEBUG_LOG("Failed to configure video for recorder");
148             return false;
149         }
150 
151         if (!ConfigureAudioParams(recorder, audioSourceId)) {
152             MEDIA_DEBUG_LOG("Failed to configure audio for recorder");
153             return false;
154         }
155 
156         if (recorder->SetMaxDuration(maxDuration)) {
157             MEDIA_DEBUG_LOG("Set Max Duration Failed");
158             return false;
159         }
160 
161         // need use fd not path
162 
163         if (recorder->SetRecorderCallback(std::make_shared<TestVideoRecorderCallback>())) {
164             MEDIA_DEBUG_LOG("Set Recorder Callback Failed");
165             return false;
166         }
167         return true;
168     }
169 }
170 
main(int argc, char **argv)171 int main(int argc, char **argv)
172 {
173     const int32_t previewFormatIndex = 1;
174     const int32_t previewWidthIndex = 2;
175     const int32_t previewHeightIndex = 3;
176     const int32_t videoFormatIndex = 4;
177     const int32_t videoWidthIndex = 5;
178     const int32_t videoHeightIndex = 6;
179     const int32_t validArgCount = 7;
180     const int32_t videoCaptureDuration = 5; // Sleep for 5 sec
181     const int32_t videoPauseDuration = 2; // Sleep for 2 sec
182     const int32_t previewVideoGap = 2; // Sleep for 2 sec
183     const char* testName = "camera_video";
184     int32_t ret = -1;
185     int32_t previewFd = -1;
186     int32_t previewFormat = CAMERA_FORMAT_YUV_420_SP;
187     int32_t previewWidth = 640;
188     int32_t previewHeight = 480;
189     int32_t videoFormat = CAMERA_FORMAT_YUV_420_SP;
190     int32_t videoWidth = 640;
191     int32_t videoHeight = 360;
192     bool isResolutionConfigured = false;
193     bool isRecorder = false;
194     Size previewsize;
195     Size videosize;
196     std::vector<int32_t> videoframerates;
197 
198     MEDIA_DEBUG_LOG("Camera new sample begin without recorder");
199     // Update sizes if enough number of valid arguments are passed
200     if (argc == validArgCount) {
201         // Validate arguments and consider if valid
202         for (int counter = 1; counter < argc; counter++) {
203             if (!TestUtils::IsNumber(argv[counter])) {
204                 cout << "Invalid argument: " << argv[counter] << endl;
205                 cout << "Retry by giving proper sizes" << endl;
206                 return 0;
207             }
208         }
209         previewFormat = atoi(argv[previewFormatIndex]);
210         previewWidth = atoi(argv[previewWidthIndex]);
211         previewHeight = atoi(argv[previewHeightIndex]);
212         videoFormat = atoi(argv[videoFormatIndex]);
213         videoWidth = atoi(argv[videoWidthIndex]);
214         videoHeight = atoi(argv[videoHeightIndex]);
215         isResolutionConfigured = true;
216     } else if (argc != 1) {
217         cout << "Pass " << (validArgCount - 1) << "arguments" << endl;
218         cout << "PreviewFormat, PreviewWidth, PreviewHeight, VideoFormat, VideoWidth, VideoHeight" << endl;
219         return 0;
220     }
221 
222     uint64_t tokenId;
223     const char *perms[0];
224     perms[0] = "ohos.permission.CAMERA";
225     NativeTokenInfoParams infoInstance = {
226         .dcapsNum = 0,
227         .permsNum = 1,
228         .aclsNum = 0,
229         .dcaps = NULL,
230         .perms = perms,
231         .acls = NULL,
232         .processName = "camera_video",
233         .aplStr = "system_basic",
234     };
235     tokenId = GetAccessTokenId(&infoInstance);
236     SetSelfTokenID(tokenId);
237     OHOS::Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo();
238 
239     sptr<CameraManager> camManagerObj = CameraManager::GetInstance();
240     MEDIA_DEBUG_LOG("Setting callback to listen camera status and flash status");
241     camManagerObj->SetCallback(std::make_shared<TestCameraMngerCallback>(testName));
242     std::vector<sptr<CameraDevice>> cameraObjList = camManagerObj->GetSupportedCameras();
243     if (cameraObjList.size() == 0) {
244         MEDIA_DEBUG_LOG("No camera devices");
245         return 0;
246     }
247 
248     MEDIA_DEBUG_LOG("Camera ID count: %{public}zu", cameraObjList.size());
249     for (auto& it : cameraObjList) {
250         MEDIA_DEBUG_LOG("Camera ID: %{public}s", it->GetID().c_str());
251     }
252 
253     sptr<CaptureSession> captureSession = camManagerObj->CreateCaptureSession();
254     if (captureSession == nullptr) {
255         MEDIA_DEBUG_LOG("Failed to create capture session");
256         return 0;
257     }
258 
259     captureSession->BeginConfig();
260 
261     sptr<CaptureInput> captureInput = camManagerObj->CreateCameraInput(cameraObjList[0]);
262     if (captureInput == nullptr) {
263         MEDIA_DEBUG_LOG("Failed to create camera input");
264         return 0;
265     }
266 
267     sptr<CameraInput> cameraInput = (sptr<CameraInput> &)captureInput;
268     cameraInput->Open();
269     if (!isResolutionConfigured) {
270         std::vector<CameraFormat> previewFormats;
271         std::vector<CameraFormat> videoFormats;
272         std::vector<Size> previewSizes;
273         std::vector<Size> videoSizes;
274         sptr<CameraOutputCapability> outputcapability =  camManagerObj->GetSupportedOutputCapability(cameraObjList[0]);
275         std::vector<Profile> previewProfiles = outputcapability->GetPreviewProfiles();
276         for (auto i : previewProfiles) {
277             previewFormats.push_back(i.GetCameraFormat());
278             previewSizes.push_back(i.GetSize());
279         }
280         MEDIA_DEBUG_LOG("Supported preview formats:");
281         for (auto &formatPreview : previewFormats) {
282             MEDIA_DEBUG_LOG("format : %{public}d", formatPreview);
283         }
284         if (std::find(previewFormats.begin(), previewFormats.end(), CAMERA_FORMAT_YUV_420_SP)
285             != previewFormats.end()) {
286             previewFormat = CAMERA_FORMAT_YUV_420_SP;
287             MEDIA_DEBUG_LOG("CAMERA_FORMAT_YUV_420_SP format is present in supported preview formats");
288         } else if (!previewFormats.empty()) {
289             previewFormat = previewFormats[0];
290             MEDIA_DEBUG_LOG("CAMERA_FORMAT_YUV_420_SP format is not present in supported preview formats");
291         }
292         std::vector<VideoProfile> videoProfiles = outputcapability->GetVideoProfiles();
293         for (auto i : videoProfiles) {
294             videoFormats.push_back(i.GetCameraFormat());
295             videoSizes.push_back(i.GetSize());
296             videoframerates = i.GetFrameRates();
297         }
298         MEDIA_DEBUG_LOG("Supported video formats:");
299         for (auto &format : videoFormats) {
300             MEDIA_DEBUG_LOG("format : %{public}d", format);
301         }
302         if (std::find(videoFormats.begin(), videoFormats.end(), CAMERA_FORMAT_YUV_420_SP)
303             != videoFormats.end()) {
304             videoFormat = CAMERA_FORMAT_YUV_420_SP;
305             MEDIA_DEBUG_LOG("CAMERA_FORMAT_YUV_420_SP format is present in supported video formats");
306         } else if (!videoFormats.empty()) {
307             videoFormat = videoFormats[0];
308             MEDIA_DEBUG_LOG("CAMERA_FORMAT_YUV_420_SP format is not present in supported video formats");
309         }
310         MEDIA_DEBUG_LOG("Supported sizes for preview:");
311         for (auto &size : previewSizes) {
312             MEDIA_DEBUG_LOG("width: %{public}d, height: %{public}d", size.width, size.height);
313         }
314         MEDIA_DEBUG_LOG("Supported sizes for video:");
315         for (auto &sizeVideo : videoSizes) {
316             MEDIA_DEBUG_LOG("width: %{public}d, height: %{public}d", sizeVideo.width, sizeVideo.height);
317         }
318         if (!previewSizes.empty()) {
319             previewWidth = previewSizes[0].width;
320             previewHeight = previewSizes[0].height;
321         }
322         if (!videoSizes.empty()) {
323             videoWidth = videoSizes[0].width;
324             videoHeight = videoSizes[0].height;
325         }
326     }
327 
328     MEDIA_DEBUG_LOG("previewFormat: %{public}d, previewWidth: %{public}d, previewHeight: %{public}d",
329                     previewFormat, previewWidth, previewHeight);
330     MEDIA_DEBUG_LOG("videoFormat: %{public}d, videoWidth: %{public}d, videoHeight: %{public}d",
331                     videoFormat, videoWidth, videoHeight);
332 
333     cameraInput->SetErrorCallback(std::make_shared<TestDeviceCallback>(testName));
334     ret = captureSession->AddInput(captureInput);
335     if (ret != 0) {
336         MEDIA_DEBUG_LOG("Add input to session is failed, ret: %{public}d", ret);
337         return 0;
338     }
339 
340     sptr<IConsumerSurface> previewSurface = IConsumerSurface::Create();
341     previewSurface->SetDefaultWidthAndHeight(previewWidth, previewHeight);
342     previewSurface->SetUserData(CameraManager::surfaceFormat, std::to_string(previewFormat));
343     previewsize.width = previewWidth;
344     previewsize.height = previewHeight;
345     Profile previewprofile = Profile(static_cast<CameraFormat>(previewFormat), previewsize);
346     sptr<SurfaceListener> listener = new SurfaceListener("Preview", SurfaceType::PREVIEW, previewFd, previewSurface);
347     previewSurface->RegisterConsumerListener((sptr<IBufferConsumerListener> &)listener);
348 
349     sptr<IBufferProducer> bp = previewSurface->GetProducer();
350     sptr<Surface> pSurface = Surface::CreateSurfaceAsProducer(bp);
351     sptr<CaptureOutput> previewOutput = camManagerObj->CreatePreviewOutput(previewprofile, pSurface);
352     if (previewOutput == nullptr) {
353         MEDIA_DEBUG_LOG("Failed to create preview output");
354         return 0;
355     }
356 
357     MEDIA_DEBUG_LOG("Setting preview callback");
358     ((sptr<PreviewOutput> &)previewOutput)->SetCallback(std::make_shared<TestPreviewOutputCallback>(testName));
359     ret = captureSession->AddOutput(previewOutput);
360     if (ret != 0) {
361         MEDIA_DEBUG_LOG("Failed to Add output to session, ret: %{public}d", ret);
362         return 0;
363     }
364 
365     sptr<Surface> videoSurface = nullptr;
366     std::shared_ptr<Recorder> recorder = nullptr;
367     if (isRecorder) {
368         int32_t videoSourceId = 0;
369         if (!CreateAndConfigureRecorder(recorder, videoSourceId, videoWidth, videoHeight)) {
370             MEDIA_DEBUG_LOG("Failed to create and configure recorder");
371             return 0;
372         }
373 
374         if (recorder->Prepare()) {
375             MEDIA_DEBUG_LOG("Failed to prepare recorder");
376             return 0;
377         }
378 
379         videoSurface = recorder->GetSurface(videoSourceId);
380         if (videoSurface == nullptr) {
381             MEDIA_DEBUG_LOG("Failed to get surface from recorder");
382             return 0;
383         }
384         videoSurface->SetUserData(CameraManager::surfaceFormat, std::to_string(videoFormat));
385     } else {
386         sptr<IConsumerSurface> cSurface = IConsumerSurface::Create();
387         sptr<SurfaceListener> videoListener = new SurfaceListener("Video", SurfaceType::VIDEO, g_videoFd, cSurface);
388         cSurface->RegisterConsumerListener((sptr<IBufferConsumerListener> &)videoListener);
389         sptr<IBufferProducer> videoProducer = cSurface->GetProducer();
390         videoSurface = Surface::CreateSurfaceAsProducer(videoProducer);
391     }
392     videosize.width = videoWidth;
393     videosize.height = videoHeight;
394     VideoProfile videoprofile = VideoProfile(static_cast<CameraFormat>(videoFormat), videosize, videoframerates);
395 
396     sptr<CaptureOutput> videoOutput = camManagerObj->CreateVideoOutput(videoprofile, videoSurface);
397     if (videoOutput == nullptr) {
398         MEDIA_DEBUG_LOG("Failed to create video output");
399         return 0;
400     }
401 
402     MEDIA_DEBUG_LOG("Setting video callback");
403     ((sptr<VideoOutput> &)videoOutput)->SetCallback(std::make_shared<TestVideoOutputCallback>(testName));
404     ret = captureSession->AddOutput(videoOutput);
405     if (ret != 0) {
406         MEDIA_DEBUG_LOG("Failed to Add output to session, ret: %{public}d", ret);
407         return 0;
408     }
409 
410     ret = captureSession->CommitConfig();
411     if (ret != 0) {
412         MEDIA_DEBUG_LOG("Failed to commit session config, ret: %{public}d", ret);
413         return 0;
414     }
415 
416     ret = captureSession->Start();
417     if (ret != 0) {
418         MEDIA_DEBUG_LOG("Failed to start session, ret: %{public}d", ret);
419         return 0;
420     }
421     sleep(previewVideoGap);
422 
423     MEDIA_DEBUG_LOG("Preview started");
424     sleep(previewVideoGap);
425     MEDIA_DEBUG_LOG("Start video recording");
426 
427     ret = ((sptr<VideoOutput> &)videoOutput)->Start();
428     if (ret != 0) {
429         MEDIA_DEBUG_LOG("Failed to start video output, ret: %{public}d", ret);
430         return 0;
431     }
432 
433     if (recorder != nullptr) {
434         ret = recorder->Start();
435         if (ret != 0) {
436             MEDIA_DEBUG_LOG("Failed to start recorder, return: %{public}s",
437                 OHOS::Media::MSErrorToString(static_cast<OHOS::Media::MediaServiceErrCode>(ret)).c_str());
438             return 0;
439         }
440     }
441 
442     MEDIA_DEBUG_LOG("Wait for 5 seconds after start");
443     sleep(videoCaptureDuration);
444     MEDIA_DEBUG_LOG("Pause video recording for 2 sec");
445     ret = ((sptr<VideoOutput> &)videoOutput)->Pause();
446     if (ret != 0) {
447         MEDIA_DEBUG_LOG("Failed to pause video output, ret: %{public}d", ret);
448         return 0;
449     }
450 
451     if (recorder != nullptr) {
452         ret = recorder->Pause();
453         if (ret != 0) {
454             MEDIA_DEBUG_LOG("Failed to pause recorder, return: %{public}s",
455                 OHOS::Media::MSErrorToString(static_cast<OHOS::Media::MediaServiceErrCode>(ret)).c_str());
456         }
457     }
458     sleep(videoPauseDuration);
459     MEDIA_DEBUG_LOG("Resume video recording");
460     ret = ((sptr<VideoOutput> &)videoOutput)->Resume();
461     if (ret != 0) {
462         MEDIA_DEBUG_LOG("Failed to resume video output, ret: %{public}d", ret);
463         return 0;
464     }
465 
466     if (recorder != nullptr) {
467         ret = recorder->Resume();
468         if (ret != 0) {
469             MEDIA_DEBUG_LOG("Failed to resume recorder, return: %{public}s",
470                 OHOS::Media::MSErrorToString(static_cast<OHOS::Media::MediaServiceErrCode>(ret)).c_str());
471         }
472     }
473     MEDIA_DEBUG_LOG("Wait for 5 seconds before stop");
474     sleep(videoCaptureDuration);
475     MEDIA_DEBUG_LOG("Stop video recording");
476     ret = ((sptr<VideoOutput> &)videoOutput)->Stop();
477     if (ret != 0) {
478         MEDIA_DEBUG_LOG("Failed to stop video output, ret: %{public}d", ret);
479         return 0;
480     }
481 
482     if (recorder != nullptr) {
483         ret = recorder->Stop(false);
484         if (ret != 0) {
485             MEDIA_DEBUG_LOG("Failed to stop recorder, return: %{public}s",
486                 OHOS::Media::MSErrorToString(static_cast<OHOS::Media::MediaServiceErrCode>(ret)).c_str());
487         }
488 
489         ret = recorder->Reset();
490         if (ret != 0) {
491             MEDIA_DEBUG_LOG("Failed to reset recorder, return: %{public}s",
492                 OHOS::Media::MSErrorToString(static_cast<OHOS::Media::MediaServiceErrCode>(ret)).c_str());
493         }
494 
495         ret = recorder->Release();
496         if (ret != 0) {
497             MEDIA_DEBUG_LOG("Failed to release recorder, return: %{public}s",
498                 OHOS::Media::MSErrorToString(static_cast<OHOS::Media::MediaServiceErrCode>(ret)).c_str());
499         }
500     }
501 
502     MEDIA_DEBUG_LOG("Closing the session");
503     ret = captureSession->Stop();
504     if (ret != 0) {
505         MEDIA_DEBUG_LOG("Failed to stop session, ret: %{public}d", ret);
506         return 0;
507     }
508 
509     MEDIA_DEBUG_LOG("Releasing the session");
510     captureSession->Release();
511 
512     // Close video file
513     TestUtils::SaveVideoFile(nullptr, 0, VideoSaveMode::CLOSE, g_videoFd);
514     cameraInput->Release();
515     camManagerObj->SetCallback(nullptr);
516     MEDIA_DEBUG_LOG("Camera new sample end.");
517     return 0;
518 }
519