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