1/*
2 * Copyright (c) 2021 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 <common.h>
17#include "camera.h"
18
19namespace OHOS::Camera {
20uint64_t Test::GetCurrentLocalTimeStamp()
21{
22    std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp =
23        std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
24    auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
25    return static_cast<uint64_t>(tmp.count());
26}
27
28void Test::CreateStreamOperatorCallback()
29{
30#ifdef CAMERA_BUILT_ON_OHOS_LITE
31    streamOperatorCallback = std::make_shared<OHOS::Camera::HdiOperatorCallback>(this);
32#else
33    streamOperatorCallback = new HdiOperatorCallback(this);
34#endif
35}
36
37void Test::CreateDeviceCallback()
38{
39#ifdef CAMERA_BUILT_ON_OHOS_LITE
40    deviceCallback = std::make_shared<CameraDeviceCallback>();
41#else
42    deviceCallback = new CameraDeviceCallback();
43#endif
44}
45
46void Test::CreateOfflineStreamOperatorCallback()
47{
48#ifdef CAMERA_BUILT_ON_OHOS_LITE
49    offlineStreamOperatorCallback = std::make_shared<OHOS::Camera::StreamOperatorCallback>();
50#else
51    offlineStreamOperatorCallback = streamOperatorCallback;
52#endif
53}
54
55void Test::StreamInfoFormat()
56{
57#ifdef CAMERA_BUILT_ON_OHOS_LITE
58    streamInfo->format_ = IMAGE_PIXEL_FORMAT_NV21;
59#else
60    streamInfo->format_ = PIXEL_FMT_YCRCB_420_SP;
61#endif
62}
63
64int32_t Test::SaveYUV(const char* type, const void* buffer, int32_t size)
65{
66    if (strncmp(type, "preview", strlen(type)) == 0) {
67        previewBufCnt += 1;
68        if (previewBufCnt % 8 != 0) { // 8:Save one frame every eight frames
69            std::cout << "receive preview buffer not save" << std::endl;
70            return 0;
71        }
72    }
73    char path[PATH_MAX] = {0};
74#ifdef CAMERA_BUILT_ON_OHOS_LITE
75    if (strncmp(type, "preview", strlen(type)) == 0) {
76        system("mkdir -p /userdata/camera");
77        char prefix[] = "/userdata/camera/";
78
79        if (sprintf_s(path, sizeof(path) / sizeof(path[0]), "%s%s_%lld.yuv",
80            prefix, type, GetCurrentLocalTimeStamp()) < 0) {
81            CAMERA_LOGE("%s: sprintf path failed", __func__);
82            return 0;
83        }
84    } else {
85        system("mkdir -p /userdata/camera");
86        char prefix[] = "/userdata/camera/";
87
88        if (sprintf_s(path, sizeof(path) / sizeof(path[0]), "%s%s_%lld.jpg",
89            prefix, type, GetCurrentLocalTimeStamp()) < 0) {
90            CAMERA_LOGE("%s: sprintf path failed", __func__);
91            return 0;
92        }
93    }
94#else
95    if (strncmp(type, "preview", strlen(type)) == 0) {
96        system("mkdir -p /data/camera/preview");
97        char prefix[] = "/data/camera/preview/";
98
99        if (sprintf_s(path, sizeof(path) / sizeof(path[0]), "%s%s_%lld.yuv",
100            prefix, type, GetCurrentLocalTimeStamp()) < 0) {
101            CAMERA_LOGE("%s: sprintf path failed", __func__);
102            return 0;
103        }
104    } else {
105        system("mkdir -p /data/camera/capture");
106        char prefix[] = "/data/camera/capture/";
107
108        if (sprintf_s(path, sizeof(path) / sizeof(path[0]), "%s%s_%lld.jpg",
109            prefix, type, GetCurrentLocalTimeStamp()) < 0) {
110            CAMERA_LOGE("%s: sprintf path failed", __func__);
111            return 0;
112        }
113    }
114#endif
115    std::cout << "save yuv to file:" << path << std::endl;
116    int imgFd = open(path, O_RDWR | O_CREAT | O_APPEND, 00766); // 00766:file jurisdiction
117    if (imgFd == -1) {
118        std::cout << "open file failed, errno = " << strerror(errno) << std::endl;
119        return -1;
120    }
121
122    int32_t ret = write(imgFd, buffer, size);
123    if (ret == -1) {
124        std::cout << "write file failed, error = " << strerror(errno) << std::endl;
125        close(imgFd);
126        return -1;
127    }
128    close(imgFd);
129    return 0;
130}
131
132int32_t Test::SaveVideoFile(const char* type, const void* buffer, int32_t size, int32_t operationMode)
133{
134    std::cout << "SaveVideoFile:  operationMode = " << operationMode << " videoFd = "<< videoFd << std::endl;
135    if (operationMode == 0) {
136        char path[PATH_MAX] = {0};
137#ifdef CAMERA_BUILT_ON_OHOS_LITE
138        system("mkdir -p /userdata/camera");
139        char prefix[] = "/userdata/camera/";
140
141        if (sprintf_s(path, sizeof(path) / sizeof(path[0]), "%s%s_%lld.h265",
142            prefix, type, GetCurrentLocalTimeStamp()) < 0) {
143            CAMERA_LOGE("%s: sprintf path failed", __func__);
144            return 0;
145        }
146#else
147        system("mkdir -p /data/camera/video");
148        char prefix[] = "/data/camera/video/";
149
150        if (sprintf_s(path, sizeof(path) / sizeof(path[0]), "%s%s_%lld.h265",
151            prefix, type, GetCurrentLocalTimeStamp()) < 0) {
152            CAMERA_LOGE("%s: sprintf path failed", __func__);
153            return 0;
154        }
155#endif
156        CAMERA_LOGI("%{public}s, save yuv to file %{public}s", __FUNCTION__, path);
157        videoFd = open(path, O_RDWR | O_CREAT, 00766); // 00766:file jurisdiction
158        if (videoFd == -1) {
159            std::cout << "open file failed, errno = " << strerror(errno) << std::endl;
160            return -1;
161        }
162    } else if (operationMode == 1 && videoFd != -1) {
163        int32_t ret = write(videoFd, buffer, size);
164        if (ret == -1) {
165            std::cout << "write file failed, error = " << strerror(errno) << std::endl;
166            close(videoFd);
167            videoFd = -1;
168            return -1;
169        }
170    } else {
171        if (videoFd != -1) {
172            close(videoFd);
173            videoFd = -1;
174        }
175    }
176    return 0;
177}
178
179void Test::Init()
180{
181#ifdef CAMERA_BUILT_ON_OHOS_LITE
182    if (service == nullptr) {
183        service = CameraHost::CreateCameraHost();
184        if (service == nullptr) {
185            std::cout << "==========[test log]ICameraHost get failed."<< std::endl;
186        } else {
187            std::cout << "==========[test log]ICameraHost get success."<< std::endl;
188        }
189    }
190    hostCallback = std::make_shared<HdiHostCallback>(this);
191#else
192    if (service == nullptr) {
193        service = ICameraHost::Get("camera_service");
194        if (service == nullptr) {
195            std::cout << "==========[test log]ICameraHost get failed."<< std::endl;
196        } else {
197            std::cout << "==========[test log]ICameraHost get success."<< std::endl;
198        }
199        ASSERT_TRUE(service != nullptr);
200    }
201    hostCallback = new HdiHostCallback(this);
202#endif
203    service->SetCallback(hostCallback);
204}
205
206void Test::GetCameraAbility()
207{
208    if (cameraDevice == nullptr) {
209        rc = service->GetCameraIds(cameraIds);
210        if (rc != Camera::NO_ERROR) {
211            std::cout << "==========[test log]GetCameraIds failed." << std::endl;
212            return;
213        } else {
214            std::cout << "==========[test log]GetCameraIds success." << std::endl;
215        }
216        GetCameraMetadata();
217    }
218}
219
220void Test::GetCameraMetadata()
221{
222    rc = service->GetCameraAbility(cameraIds.front(), ability);
223    if (rc != Camera::NO_ERROR) {
224        std::cout << "==========[test log]GetCameraAbility failed, rc = " << rc << std::endl;
225    }
226    common_metadata_header_t* data = ability->get();
227    camera_metadata_item_t entry;
228    int ret = FindCameraMetadataItem(data, OHOS_CONTROL_AE_AVAILABLE_MODES, &entry);
229    if (ret == 0) {
230        std::cout << "==========[test log] get OHOS_CONTROL_AE_AVAILABLE_MODES success" << std::endl;
231    }
232}
233
234void Test::Open()
235{
236    if (cameraDevice == nullptr) {
237        service->GetCameraIds(cameraIds);
238#ifdef CAMERA_BUILT_ON_OHOS_LITE
239        deviceCallback = std::make_shared<HdiDeviceCallback>(this);
240#else
241        deviceCallback = new HdiDeviceCallback(this);
242#endif
243        rc = service->OpenCamera(cameraIds.front(), deviceCallback, cameraDevice);
244        if (rc != Camera::NO_ERROR || cameraDevice == nullptr) {
245            std::cout << "==========[test log]OpenCamera failed, rc = " << rc << std::endl;
246            return;
247        }
248        std::cout << "==========[test log]OpenCamera success." << std::endl;
249        GetCameraMetadata();
250    }
251}
252
253void Test::Close()
254{
255    if (cameraDevice != nullptr) {
256        cameraDevice->Close();
257        std::cout << "cameraDevice->Close" << std::endl;
258        cameraDevice = nullptr;
259    }
260}
261
262void Test::StartStream(std::vector<Camera::StreamIntent> intents)
263{
264    EXPECT_EQ(true, cameraDevice != nullptr);
265    CreateStreamOperatorCallback();
266    rc = cameraDevice->GetStreamOperator(streamOperatorCallback, streamOperator);
267    EXPECT_EQ(true, rc == Camera::NO_ERROR);
268    if (rc == Camera::NO_ERROR) {
269        std::cout << "==========[test log]GetStreamOperator success." << std::endl;
270    } else {
271        std::cout << "==========[test log]GetStreamOperator fail, rc = " << rc << std::endl;
272    }
273    streamInfo = std::make_shared<Camera::StreamInfo>();
274    streamInfo_video = std::make_shared<Camera::StreamInfo>();
275    streamInfo_capture = std::make_shared<Camera::StreamInfo>();
276    for (const auto& intent : intents) {
277        if (intent == 0) {
278            streamInfo->streamId_ = streamId_preview;
279            streamInfo->width_ = 640; // 640:width of stream
280            streamInfo->height_ = 480; // 480: height of stream
281            streamInfo->dataspace_ = 8; // 8:dataspace of stream
282            streamInfo->intent_ = intent;
283            streamInfo->tunneledMode_ = 5; // 5:tunneledMode of stream
284            StreamInfoFormat();
285            std::shared_ptr<StreamConsumer> consumer_pre = std::make_shared<StreamConsumer>();
286            std::cout << "==========[test log]received a preview buffer ... 0" << std::endl;
287#ifdef CAMERA_BUILT_ON_OHOS_LITE
288            streamInfo->bufferQueue_ = consumer_pre->CreateProducer([this](OHOS::SurfaceBuffer* buffer) {
289                SaveYUV("preview", buffer->GetVirAddr(), buffer->GetSize());
290            });
291#else
292            streamInfo->bufferQueue_ = consumer_pre->CreateProducer([this](void* addr, uint32_t size) {
293                SaveYUV("preview", addr, size);
294            });
295#endif
296            streamInfo->bufferQueue_->SetQueueSize(8); // 8:bufferqueue size
297            consumerMap_[intent] = consumer_pre;
298            streamInfos.push_back(streamInfo);
299        } else if (intent == 1) {
300            streamInfo_video->streamId_ = streamId_video;
301            streamInfo_video->width_ = 1280; // 1280:width of stream
302            streamInfo_video->height_ = 960; // 960: height of stream
303            streamInfo_video->dataspace_ = 8; // 8:dataspace of stream
304            streamInfo_video->intent_ = intent;
305            streamInfo_video->encodeType_ = ENCODE_TYPE_H265;
306            streamInfo_video->tunneledMode_ = 5; // 5:tunneledMode of stream
307#ifdef CAMERA_BUILT_ON_OHOS_LITE
308            streamInfo_video->format_ = IMAGE_PIXEL_FORMAT_NV21;
309#else
310            streamInfo_video->format_ = PIXEL_FMT_YCRCB_420_SP;
311#endif
312            std::shared_ptr<StreamConsumer> consumer_video = std::make_shared<StreamConsumer>();
313            std::cout << "==========[test log]received a video buffer ... 1" << std::endl;
314            SaveVideoFile("video", nullptr, 0, 0);
315#ifdef CAMERA_BUILT_ON_OHOS_LITE
316            streamInfo_video->bufferQueue_ = consumer_video->CreateProducer([this](OHOS::SurfaceBuffer* buffer) {
317                int32_t size = 0;
318                buffer->GetInt32(OHOS::Camera::VIDEO_KEY_INFO_DATA_SIZE, size);
319                SaveVideoFile("video", buffer->GetVirAddr(), size, 1);
320            });
321#else
322            streamInfo_video->bufferQueue_ = consumer_video->CreateProducer([this](void* addr, uint32_t size) {
323                SaveVideoFile("video", addr, size, 1);
324            });
325#endif
326            streamInfo_video->bufferQueue_->SetQueueSize(8); // 8:bufferqueue size
327            consumerMap_[intent] = consumer_video;
328            streamInfos.push_back(streamInfo_video);
329        } else {
330            streamInfo_capture->streamId_ = streamId_capture;
331            streamInfo_capture->width_ = 1280; // 1280:width of stream
332            streamInfo_capture->height_ = 960; // 960: height of stream
333            streamInfo_capture->dataspace_ = 8; // 8:dataspace of stream
334            streamInfo_capture->intent_ = intent;
335            streamInfo_capture->encodeType_ = ENCODE_TYPE_JPEG;
336            streamInfo_capture->tunneledMode_ = 5; // 5:tunneledMode of stream
337#ifdef CAMERA_BUILT_ON_OHOS_LITE
338            streamInfo_capture->format_ = IMAGE_PIXEL_FORMAT_NV21;
339#else
340            streamInfo_capture->format_ = PIXEL_FMT_YCRCB_420_SP;
341#endif
342            std::shared_ptr<StreamConsumer> consumer_capture = std::make_shared<StreamConsumer>();
343            std::cout << "==========[test log]received a capture buffer ... 2" << std::endl;
344#ifdef CAMERA_BUILT_ON_OHOS_LITE
345            streamInfo_capture->bufferQueue_ = consumer_capture->CreateProducer([this](OHOS::SurfaceBuffer* buffer) {
346                SaveYUV("capture", buffer->GetVirAddr(), buffer->GetSize());
347            });
348#else
349            streamInfo_capture->bufferQueue_ = consumer_capture->CreateProducer([this](void* addr, uint32_t size) {
350                SaveYUV("capture", addr, size);
351            });
352#endif
353            streamInfo_capture->bufferQueue_->SetQueueSize(8); // 8:bufferqueue size
354            consumerMap_[intent] = consumer_capture;
355            streamInfos.push_back(streamInfo_capture);
356        }
357    }
358    rc = streamOperator->CreateStreams(streamInfos);
359    EXPECT_EQ(false, rc != Camera::NO_ERROR);
360    if (rc == Camera::NO_ERROR) {
361        std::cout << "==========[test log]CreateStreams success." << std::endl;
362    } else {
363        std::cout << "==========[test log]CreateStreams fail, rc = " << rc << std::endl;
364    }
365
366    rc = streamOperator->CommitStreams(Camera::NORMAL, ability);
367    EXPECT_EQ(false, rc != Camera::NO_ERROR);
368    if (rc == Camera::NO_ERROR) {
369        std::cout << "==========[test log]CommitStreams success." << std::endl;
370    } else {
371        std::cout << "==========[test log]CommitStreams fail, rc = " << rc << std::endl;
372    }
373    sleep(2); // 2:The program waits two seconds
374    std::vector<std::shared_ptr<Camera::StreamInfo>>().swap(streamInfos);
375}
376
377void Test::StartCapture(int streamId, int captureId, bool shutterCallback, bool isStreaming)
378{
379    captureInfo = std::make_shared<Camera::CaptureInfo>();
380    captureInfo->streamIds_.push_back(streamId);
381    captureInfo->captureSetting_ = ability;
382    captureInfo->enableShutterCallback_ = shutterCallback;
383    rc = streamOperator->Capture(captureId, captureInfo, isStreaming);
384    EXPECT_EQ(true, rc == Camera::NO_ERROR);
385    if (rc == Camera::NO_ERROR) {
386        std::cout << "==========[test log]check Capture: Capture success, " << captureId << std::endl;
387    } else {
388        std::cout << "==========[test log]check Capture: Capture fail, rc = " << rc << std::endl;
389    }
390    sleep(1); // 1:Wait 1 seconds for the program to run
391}
392
393void Test::StopStream(std::vector<int>& captureIds, std::vector<int>& streamIds)
394{
395    if (captureIds.size() > 0) {
396        std::cout << "captureIds.size() = " << captureIds.size() << std::endl;
397        for (auto &captureId : captureIds) {
398            std::cout << "captureId = " << captureId << std::endl;
399            rc = streamOperator->CancelCapture(captureId);
400            EXPECT_EQ(true, rc == Camera::NO_ERROR);
401            if (rc == Camera::NO_ERROR) {
402                std::cout << "==========[test log]check Capture: CancelCapture success," << captureId << std::endl;
403            } else {
404                std::cout << "==========[test log]check Capture: CancelCapture fail, rc = " << rc << std::endl;
405                std::cout << "captureId = " << captureId << std::endl;
406            }
407            if (captureId == captureId_preview) {
408                captureId_preview++;
409            } else if (captureId == captureId_capture) {
410                captureId_capture++;
411            } else if (captureId == captureId_video) {
412                captureId_video++;
413            }
414        }
415    }
416    SaveVideoFile("video", nullptr, 0, 2); // 2:Operation Mode
417    if (streamIds.size() > 0) {
418        rc = streamOperator->ReleaseStreams(streamIds);
419        EXPECT_EQ(true, rc == Camera::NO_ERROR);
420        if (rc == Camera::NO_ERROR) {
421            std::cout << "==========[test log]check Capture: ReleaseStreams success." << std::endl;
422        } else {
423            std::cout << "==========[test log]check Capture: ReleaseStreams fail, rc = " << rc << std::endl;
424        }
425    }
426    streamIds.clear();
427}
428
429void Test::StopConsumer(std::vector<Camera::StreamIntent> intents)
430{
431    for (const auto& intent : intents) {
432        consumerMap_[intent]->StopConsumer();
433    }
434}
435
436void Test::StopOfflineStream(int captureId)
437{
438    captureId--;
439    rc = offlineStreamOperator->CancelCapture(captureId);
440    EXPECT_EQ(rc, Camera::NO_ERROR);
441    if (rc == Camera::NO_ERROR) {
442        std::cout << "==========[test log]check offline: CancelCapture success," << captureId << std::endl;
443    } else {
444        std::cout << "==========[test log]check offline: CancelCapture fail, rc = " << rc;
445        std::cout << "captureId = " << captureId << std::endl;
446    }
447    rc = offlineStreamOperator->Release();
448    EXPECT_EQ(rc, Camera::NO_ERROR);
449    if (rc == Camera::NO_ERROR) {
450        std::cout << "==========[test log]Check offline stream: offline Release success." << std::endl;
451    } else {
452        std::cout << "==========[test log]Check offline stream: offline Release fail, rc = " << rc << std::endl;
453    }
454}
455
456#ifdef CAMERA_BUILT_ON_OHOS_LITE
457std::shared_ptr<OHOS::Surface> Test::StreamConsumer::CreateProducer(std::function<void(OHOS::SurfaceBuffer*)> callback)
458{
459    Surface* surface = OHOS::Surface::CreateSurface();
460    consumer_ = std::shared_ptr<OHOS::Surface>(surface);
461    if (consumer_ == nullptr) {
462        return nullptr;
463    }
464    callback_ = callback;
465
466    consumerThread_ = new std::thread([this] {
467        while (running_ == true) {
468            OHOS::SurfaceBuffer* buffer = consumer_->AcquireBuffer();
469            if (buffer != nullptr) {
470                if (callback_ != nullptr) {
471                    callback_(buffer);
472                }
473                consumer_->ReleaseBuffer(buffer);
474            }
475        }
476    });
477    return consumer_;
478}
479#else
480OHOS::sptr<OHOS::IBufferProducer> Test::StreamConsumer::CreateProducer(std::function<void(void*, uint32_t)> callback)
481{
482    consumer_ = OHOS::Surface::CreateSurfaceAsConsumer();
483    if (consumer_ == nullptr) {
484        return nullptr;
485    }
486    sptr<IBufferConsumerListener> listener = new TestBufferConsumerListener();
487    CHECK_IF_PTR_NULL_RETURN_VALUE(listener, nullptr);
488    consumer_->RegisterConsumerListener(listener);
489    auto producer = consumer_->GetProducer();
490    std::cout << "create a buffer queue producer:" << producer.GetRefPtr() << std::endl;
491    if (producer == nullptr) {
492        return nullptr;
493    }
494    callback_ = callback;
495    running_ = true;
496    consumerThread_ = new std::thread([this] {
497        int32_t flushFence = 0;
498        int64_t timestamp = 0;
499        OHOS::Rect damage;
500        OHOS::BufferRequestConfig config;
501        while (running_ == true) {
502            OHOS::sptr<OHOS::SurfaceBuffer> buffer = nullptr;
503            consumer_->AcquireBuffer(buffer, flushFence, timestamp, damage);
504            if (buffer != nullptr) {
505                void* addr = buffer->GetVirAddr();
506                uint32_t size = buffer->GetSize();
507                uint64_t pa = buffer->GetPhyAddr();
508                CAMERA_LOGI("consumer receive buffer add = %{public}llu", pa);
509                if (callback_ != nullptr) {
510                    callback_(addr, size);
511                }
512                consumer_->ReleaseBuffer(buffer, -1);
513                CAMERA_LOGI("consumer release buffer add = %{public}llu", pa);
514                shotCount_--;
515                if (shotCount_ == 0) {
516                    std::unique_lock<std::mutex> l(l_);
517                    cv_.notify_one();
518                }
519            }
520            if (running_ == false) {
521                break;
522            }
523        }
524        return;
525    });
526    return producer;
527}
528#endif
529
530void Test::StreamConsumer::StopConsumer()
531{
532    running_ = false;
533}
534}
535