1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file expected 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 "hdi_common.h"
17#include "camera.h"
18#include "video_key_info.h"
19
20namespace OHOS::Camera {
21HdiCommon::ResultCallback HdiCommon::resultCallback_ = 0;
22
23uint64_t HdiCommon::GetCurrentLocalTimeStamp()
24{
25    std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp =
26        std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
27    auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
28    return static_cast<uint64_t>(tmp.count());
29}
30
31int32_t HdiCommon::DumpImageFile(int streamId, std::string suffix, const void* buffer, int32_t size)
32{
33    if (imageDataSaveSwitch == SWITCH_OFF) {
34        return 0;
35    }
36    if (streamId < 0) {
37        CAMERA_LOGE("ivalid stream id: %{public}d", streamId);
38        return -1;
39    }
40    char mkdirCmd[PATH_MAX] = {0};
41    char path[PATH_MAX] = {0};
42    int ret = sprintf_s(mkdirCmd, sizeof(mkdirCmd) / sizeof(mkdirCmd[0]),
43        "mkdir -p /data/stream-%d", streamId);
44    if (ret < 0) {
45        return -1;
46    }
47    system(mkdirCmd);
48    ret = sprintf_s(path, sizeof(path) / sizeof(path[0]), "data/stream-%d/%lld.%s",
49        streamId, GetCurrentLocalTimeStamp(), suffix.c_str());
50    if (ret < 0) {
51        return -1;
52    }
53
54    int imgFd = open(path, O_RDWR | O_CREAT, 00766);
55    if (imgFd == -1) {
56        CAMERA_LOGE("open file failed, errno: %{public}s", strerror(errno));
57        return -1;
58    }
59
60    ret = write(imgFd, buffer, size);
61    if (ret == -1) {
62        CAMERA_LOGE("write file failed, error: %{public}s", strerror(errno));
63        close(imgFd);
64        return -1;
65    }
66    close(imgFd);
67    return 0;
68}
69
70void HdiCommon::Init()
71{
72    if (service == nullptr) {
73        service = ICameraHost::Get("camera_service", false);
74        if (service == nullptr)  {
75            printf("ICameraHost get failed\n");
76            CAMERA_LOGE("ICameraHost get failed");
77            return;
78        }
79    }
80    hostCallback = new TestCameraHostCallback();
81    service->SetCallback(hostCallback);
82}
83
84void HdiCommon::GetCameraMetadata()
85{
86    rc = service->GetCameraAbility(cameraIds.front(), abilityVec);
87    if (rc != HDI::Camera::V1_0::NO_ERROR) {
88        printf("GetCameraAbility failed, rc = %d\n", rc);
89        CAMERA_LOGE("GetCameraAbility failed, rc = %{public}d", rc);
90        return;
91    }
92    MetadataUtils::ConvertVecToMetadata(abilityVec, ability);
93
94    common_metadata_header_t* data = ability->get();
95    camera_metadata_item_t entry;
96    int ret = FindCameraMetadataItem(data, OHOS_CONTROL_AE_AVAILABLE_MODES, &entry);
97    camera_metadata_item_t connectEntry;
98    ret = FindCameraMetadataItem(data, OHOS_ABILITY_CAMERA_CONNECTION_TYPE, &connectEntry);
99    if (ret == HDI::Camera::V1_0::NO_ERROR && connectEntry.data.u8 != nullptr && connectEntry.count > 0) {
100        uint8_t cameraConnectionType = *(connectEntry.data.u8);
101        if (static_cast<int>(cameraConnectionType) == OHOS_CAMERA_CONNECTION_TYPE_USB_PLUGIN) {
102            CAMERA_LOGI("get OHOS_ABILITY_CAMERA_CONNECTION_TYPE success, this camera is usb camera.");
103            previewWidth = usbCamera_previewWidth;
104            previewHeight = usbCamera_previewHeight;
105            videoWidth = usbCamera_videoWidth;
106            videoHeight = usbCamera_videoHeight;
107            captureWidth = usbCamera_captureWidth;
108            captureHeight = usbCamera_captureHeight;
109            analyzeWidth = usbCamera_analyzeWidth;
110            analyzeHeight = usbCamera_analyzeHeight;
111            previewFormat = usbCamera_previewFormat;
112            videoFormat = usbCamera_videoFormat;
113            snapshotFormat = usbCamera_snapshotFormat;
114            analyzeFormat = usbCamera_analyzeFormat;
115            videoEncodeType = usbCamera_videoEncodeType;
116        }
117    }
118}
119
120void HdiCommon::Open()
121{
122    if (cameraDevice == nullptr) {
123        service->GetCameraIds(cameraIds);
124        if (cameraIds.size() == 0) {
125            printf("camera device list empty\n");
126            CAMERA_LOGE("camera device list empty");
127            return;
128        }
129        GetCameraMetadata();
130        deviceCallback = new OHOS::Camera::HdiCommon::DemoCameraDeviceCallback();
131        rc = service->OpenCamera(cameraIds.front(), deviceCallback, cameraDevice);
132        if (rc != HDI::Camera::V1_0::NO_ERROR || cameraDevice == nullptr) {
133            printf("openCamera failed, rc = %d\n", rc);
134            CAMERA_LOGE("openCamera failed, rc = %{public}d", rc);
135            return;
136        }
137        CAMERA_LOGI("OpenCamera success");
138    }
139}
140
141void HdiCommon::Close()
142{
143    if (cameraDevice != nullptr) {
144        cameraDevice->Close();
145        cameraDevice = nullptr;
146    }
147}
148
149void HdiCommon::DefaultPreview(std::shared_ptr<StreamInfo> &infos)
150{
151    infos->streamId_ = streamIdPreview;
152    infos->width_ = previewWidth;
153    infos->height_ = previewHeight;
154    infos->format_ = previewFormat;
155    infos->dataspace_ = UT_DATA_SIZE;
156    infos->intent_ = StreamIntent::PREVIEW;
157    infos->tunneledMode_ = UT_TUNNEL_MODE;
158}
159
160void HdiCommon::DefaultCapture(std::shared_ptr<StreamInfo> &infos)
161{
162    infos->streamId_ = streamIdCapture;
163    infos->width_ = captureWidth;
164    infos->height_ = captureHeight;
165    infos->format_ = snapshotFormat;
166    infos->dataspace_ = UT_DATA_SIZE;
167    infos->intent_ = StreamIntent::STILL_CAPTURE;
168    infos->tunneledMode_ = UT_TUNNEL_MODE;
169}
170
171void HdiCommon::DefaultInfosPreview(std::shared_ptr<StreamInfo> &infos)
172{
173    DefaultPreview(infos);
174    std::shared_ptr<OHOS::Camera::HdiCommon::StreamConsumer> consumer_pre =
175        std::make_shared<OHOS::Camera::HdiCommon::StreamConsumer>();
176    infos->bufferQueue_ = consumer_pre->CreateProducerSeq([this](void* addr, uint32_t size) {
177        DumpImageFile(streamIdPreview, "yuv", addr, size);
178    });
179    infos->bufferQueue_->producer_->SetQueueSize(UT_DATA_SIZE);
180    consumerMap_[StreamIntent::PREVIEW] = consumer_pre;
181}
182
183void HdiCommon::DefaultInfosCapture(std::shared_ptr<StreamInfo> &infos)
184{
185    DefaultCapture(infos);
186    std::shared_ptr<OHOS::Camera::HdiCommon::StreamConsumer> consumer_capture =
187        std::make_shared<OHOS::Camera::HdiCommon::StreamConsumer>();
188    infos->bufferQueue_ = consumer_capture->CreateProducerSeq([this](void* addr, uint32_t size) {
189        DumpImageFile(streamIdPreview, "yuv", addr, size);
190    });
191    infos->bufferQueue_->producer_->SetQueueSize(UT_DATA_SIZE);
192    consumerMap_[StreamIntent::PREVIEW] = consumer_capture;
193}
194
195void HdiCommon::DefaultInfosVideo(std::shared_ptr<StreamInfo> &infos)
196{
197    infos->streamId_ = streamIdVideo;
198    infos->width_ = videoWidth;
199    infos->height_ = videoHeight;
200    infos->format_ = videoFormat;
201    infos->dataspace_ = UT_DATA_SIZE;
202    infos->intent_ = StreamIntent::VIDEO;
203    infos->encodeType_ = static_cast<OHOS::HDI::Camera::V1_0::EncodeType>(videoEncodeType);
204    infos->tunneledMode_ = UT_TUNNEL_MODE;
205    std::shared_ptr<OHOS::Camera::HdiCommon::StreamConsumer> consumer_video =
206        std::make_shared<OHOS::Camera::HdiCommon::StreamConsumer>();
207    infos->bufferQueue_ = consumer_video->CreateProducerSeq([this](void* addr, uint32_t size) {
208        DumpImageFile(streamIdVideo, "yuv", addr, size);
209    });
210    infos->bufferQueue_->producer_->SetQueueSize(UT_DATA_SIZE);
211    consumerMap_[StreamIntent::VIDEO] = consumer_video;
212}
213
214void HdiCommon::DefaultInfosAnalyze(std::shared_ptr<StreamInfo> &infos)
215{
216    infos->streamId_ = streamIdAnalyze;
217    infos->width_ = analyzeWidth;
218    infos->height_ = analyzeHeight;
219    infos->format_ = analyzeFormat;
220    infos->dataspace_ = UT_DATA_SIZE;
221    infos->intent_ = StreamIntent::ANALYZE;
222    infos->tunneledMode_ = UT_TUNNEL_MODE;
223
224    std::shared_ptr<OHOS::Camera::HdiCommon::StreamConsumer> consumer_analyze =
225        std::make_shared<OHOS::Camera::HdiCommon::StreamConsumer>();
226    infos->bufferQueue_ = consumer_analyze->CreateProducerSeq([this](void* addr, uint32_t size) {
227        common_metadata_header_t *data = static_cast<common_metadata_header_t *>(addr);
228        camera_metadata_item_t entry = {};
229
230        int ret = FindCameraMetadataItem(data, OHOS_STATISTICS_FACE_IDS, &entry);
231        if (ret == 0) {
232            for (size_t i = 0; i < entry.count; i++) {
233                int id = entry.data.i32[i];
234                CAMERA_LOGI("Face ids : %{public}d", id);
235            }
236        }
237
238        ret = FindCameraMetadataItem(data, OHOS_STATISTICS_FACE_RECTANGLES, &entry);
239        if (ret == 0) {
240            for (size_t i = 0; i < entry.count; i++) {
241                int id = entry.data.i32[i];
242                CAMERA_LOGI("Face rectangles : %{public}d", id);
243            }
244        }
245    });
246    infos->bufferQueue_->producer_->SetQueueSize(UT_DATA_SIZE);
247    consumerMap_[StreamIntent::ANALYZE] = consumer_analyze;
248}
249
250void HdiCommon::StartStream(std::vector<StreamIntent> intents)
251{
252    streamOperatorCallback = new TestStreamOperatorCallback();
253    rc = cameraDevice->GetStreamOperator(streamOperatorCallback, streamOperator);
254    if (rc != HDI::Camera::V1_0::NO_ERROR) {
255        printf("GetStreamOperator fail, rc = %d\n", rc);
256        CAMERA_LOGE("GetStreamOperator fail, rc = %{public}d", rc);
257        return;
258    }
259    streamInfoPre = std::make_shared<StreamInfo>();
260    streamInfoVideo = std::make_shared<StreamInfo>();
261    streamInfoCapture = std::make_shared<StreamInfo>();
262    streamInfoAnalyze = std::make_shared<StreamInfo>();
263    for (auto& intent : intents) {
264        if (intent == StreamIntent::PREVIEW) {
265            DefaultInfosPreview(streamInfoPre);
266            streamInfos.push_back(*streamInfoPre);
267        } else if (intent == StreamIntent::VIDEO) {
268            DefaultInfosVideo(streamInfoVideo);
269            streamInfos.push_back(*streamInfoVideo);
270        } else if (intent == StreamIntent::ANALYZE) {
271            DefaultInfosAnalyze(streamInfoAnalyze);
272            streamInfos.push_back(*streamInfoAnalyze);
273        } else {
274            DefaultInfosCapture(streamInfoCapture);
275            streamInfos.push_back(*streamInfoCapture);
276        }
277    }
278
279    rc = streamOperator->CreateStreams(streamInfos);
280    if (rc != HDI::Camera::V1_0::NO_ERROR) {
281        printf("check StartStream: CreateStreams fail, rc = %d\n", rc);
282        CAMERA_LOGE("check StartStream: CreateStreams fail, rc = %{public}d", rc);
283    }
284    rc = streamOperator->CommitStreams(OperationMode::NORMAL, abilityVec);
285    if (rc != HDI::Camera::V1_0::NO_ERROR) {
286        printf("check StartStream: CommitStreams fail, rc = %d\n", rc);
287        CAMERA_LOGE("check StartStream: CommitStreams fail, rc = %{public}d", rc);
288    }
289    sleep(1);
290    std::vector<StreamInfo>().swap(streamInfos);
291}
292
293void HdiCommon::StartCapture(int streamId, int captureId, bool shutterCallback, bool isStreaming)
294{
295    captureInfo = std::make_shared<CaptureInfo>();
296    captureInfo->streamIds_ = {streamId};
297    captureInfo->captureSetting_ = abilityVec;
298    captureInfo->enableShutterCallback_ = shutterCallback;
299    rc = streamOperator->Capture(captureId, *captureInfo, isStreaming);
300    if (rc != HDI::Camera::V1_0::NO_ERROR) {
301        printf("check Capture: Capture fail, rc = %d\n", rc);
302        CAMERA_LOGE("check Capture: Capture fail, rc = %{public}d", rc);
303    }
304    sleep(UT_SLEEP_TIME);
305}
306
307void HdiCommon::StopStream(std::vector<int>& captureIds, std::vector<int>& streamIds)
308{
309    if (captureIds.size() > 0) {
310        for (auto &captureId : captureIds) {
311            rc = streamOperator->CancelCapture(captureId);
312            if (rc != HDI::Camera::V1_0::NO_ERROR) {
313                printf("check CancelCapture fail, rc = %d, captureId = %d\n", rc, captureId);
314                CAMERA_LOGE("check CancelCapture fail, rc = %{public}d, captureId = %{public}d", rc, captureId);
315            }
316        }
317    }
318    if (streamIds.size() > 0) {
319        rc = streamOperator->ReleaseStreams(streamIds);
320        if (rc != HDI::Camera::V1_0::NO_ERROR) {
321            printf("check Capture: ReleaseStreams fail, rc = %d\n", rc);
322            CAMERA_LOGE("check Capture: ReleaseStreams fail, rc = %{public}d", rc);
323        }
324    }
325}
326
327void HdiCommon::StreamConsumer::CalculateFps(int64_t timestamp, int32_t streamId)
328{
329    if (isFirstCalculateFps_) {
330        if ((timestamp - intervalTimestamp_) >= interval_) {
331            int64_t timeInterval = timestamp - intervalTimestamp_;
332            if (timeInterval != 0) {
333                float fps = (int64_t)(100000000000 * timestampCount_ / timeInterval) / 100.0;
334                CAMERA_LOGI("Calculate FPS success, streamId: %{public}d, Fps:%{public}f", streamId, fps);
335                interval_ = ONESECOND_OF_MICROSECOND_UNIT;
336            } else {
337                CAMERA_LOGE("Calculate FPS error timeInerval is 0");
338            }
339        }
340    } else {
341        intervalTimestamp_ = timestamp;
342        isFirstCalculateFps_ = true;
343    }
344    if ((timestamp - intervalTimestamp_) >= ONESECOND_OF_MICROSECOND_UNIT * UT_SECOND_TIMES) {
345        intervalTimestamp_ = timestamp;
346        timestampCount_ = 0;
347        interval_ = ONESECOND_OF_MICROSECOND_UNIT;
348    }
349    timestampCount_++;
350}
351
352OHOS::sptr<OHOS::IBufferProducer> HdiCommon::StreamConsumer::CreateProducer(
353    std::function<void(void*, uint32_t)> callback)
354{
355    consumer_ = OHOS::IConsumerSurface::Create();
356    if (consumer_ == nullptr) {
357        return nullptr;
358    }
359    sptr<IBufferConsumerListener> listener = new TestBufferConsumerListener();
360    consumer_->RegisterConsumerListener(listener);
361    auto producer = consumer_->GetProducer();
362    if (producer == nullptr) {
363        return nullptr;
364    }
365
366    callback_ = callback;
367    consumerThread_ = new std::thread([this, listener] {
368        int32_t flushFence = 0;
369        int64_t timestamp = 0;
370        OHOS::Rect damage;
371        TestBufferConsumerListener* checker = static_cast<TestBufferConsumerListener*>(listener.GetRefPtr());
372        while (running_ == true) {
373            OHOS::sptr<OHOS::SurfaceBuffer> buffer = nullptr;
374            if (checker->checkBufferAvailable()) {
375                consumer_->AcquireBuffer(buffer, flushFence, timestamp, damage);
376                if (buffer != nullptr) {
377                    void* addr = buffer->GetVirAddr();
378                    uint32_t size = buffer->GetSize();
379
380                    int32_t gotSize = 0;
381                    int32_t isKey = 0;
382                    int32_t streamId = 0;
383                    int32_t captureId = 0;
384                    buffer->GetExtraData()->ExtraGet(OHOS::Camera::dataSize, gotSize);
385                    buffer->GetExtraData()->ExtraGet(OHOS::Camera::isKeyFrame, isKey);
386                    buffer->GetExtraData()->ExtraGet(OHOS::Camera::timeStamp, timestamp);
387                    buffer->GetExtraData()->ExtraGet(OHOS::Camera::streamId, streamId);
388                    buffer->GetExtraData()->ExtraGet(OHOS::Camera::captureId, captureId);
389                    if (gotSize) {
390                        CalculateFps(timestamp, streamId);
391                        callback_(addr, gotSize);
392                    } else {
393                        callback_(addr, size);
394                    }
395
396                    consumer_->ReleaseBuffer(buffer, -1);
397                    shotCount_--;
398                    if (shotCount_ == 0) {
399                        std::unique_lock<std::mutex> l(l_);
400                        cv_.notify_one();
401                    }
402                }
403            }
404            if (running_ == false) {
405                break;
406            }
407            usleep(1);
408        }
409    });
410
411    return producer;
412}
413
414OHOS::sptr<BufferProducerSequenceable> HdiCommon::StreamConsumer::CreateProducerSeq(
415    std::function<void(void*, uint32_t)> callback)
416{
417    OHOS::sptr<OHOS::IBufferProducer> producer = CreateProducer(callback);
418    if (producer == nullptr) {
419        return nullptr;
420    }
421
422    return new BufferProducerSequenceable(producer);
423}
424
425int32_t HdiCommon::TestStreamOperatorCallback::OnCaptureStarted(
426    int32_t captureId, const std::vector<int32_t> &streamId)
427{
428    for (auto it : streamId) {
429        CAMERA_LOGE("captureId: %{public}d, streamId: %{public}d", captureId, it);
430    }
431    return HDI::Camera::V1_0::NO_ERROR;
432}
433
434int32_t HdiCommon::TestStreamOperatorCallback::OnCaptureEnded(
435    int32_t captureId, const std::vector<CaptureEndedInfo> &infos)
436{
437    for (auto it : infos) {
438        CAMERA_LOGE("captureId: %{public}d, streamId: %{public}d, count: %{public}d", captureId, it.streamId_,
439            it.frameCount_);
440    }
441    return HDI::Camera::V1_0::NO_ERROR;
442}
443
444int32_t HdiCommon::TestStreamOperatorCallback::OnCaptureError(
445    int32_t captureId, const std::vector<CaptureErrorInfo> &infos)
446{
447    for (auto it : infos) {
448        CAMERA_LOGE("captureId: %{public}d, streamId: %{public}d, error: %{public}d", captureId, it.streamId_,
449            it.error_);
450    }
451    return HDI::Camera::V1_0::NO_ERROR;
452}
453
454int32_t HdiCommon::TestStreamOperatorCallback::OnFrameShutter(int32_t captureId,
455    const std::vector<int32_t> &streamIds, uint64_t timestamp)
456{
457    (void)timestamp;
458    for (auto it : streamIds) {
459        CAMERA_LOGE("captureId: %{public}d, streamId: %{public}d", captureId, it);
460    }
461    return HDI::Camera::V1_0::NO_ERROR;
462}
463
464int32_t HdiCommon::DemoCameraDeviceCallback::OnError(ErrorType type, int32_t errorMsg)
465{
466    CAMERA_LOGE("type: %{public}d, errorMsg: %{public}d", type, errorMsg);
467    return HDI::Camera::V1_0::NO_ERROR;
468}
469
470int32_t HdiCommon::DemoCameraDeviceCallback::OnResult(uint64_t timestamp, const std::vector<uint8_t> &result)
471{
472    if (HdiCommon::resultCallback_) {
473        std::shared_ptr<CameraMetadata> resultMeta;
474        MetadataUtils::ConvertVecToMetadata(result, resultMeta);
475        HdiCommon::resultCallback_(timestamp, resultMeta);
476    }
477    return HDI::Camera::V1_0::NO_ERROR;
478}
479
480int32_t HdiCommon::TestCameraHostCallback::OnCameraStatus(const std::string& cameraId, CameraStatus status)
481{
482    CAMERA_LOGE("cameraId: %{public}s, status: %{public}d", cameraId.c_str(), status);
483    return HDI::Camera::V1_0::NO_ERROR;
484}
485
486int32_t HdiCommon::TestCameraHostCallback::OnFlashlightStatus(const std::string& cameraId, FlashlightStatus status)
487{
488    CAMERA_LOGE("cameraId: %{public}s, status: %{public}d", cameraId.c_str(), status);
489    return HDI::Camera::V1_0::NO_ERROR;
490}
491
492int32_t HdiCommon::TestCameraHostCallback::OnCameraEvent(const std::string& cameraId, CameraEvent event)
493{
494    CAMERA_LOGE("cameraId: %{public}s, status: %{public}d", cameraId.c_str(), event);
495    return HDI::Camera::V1_0::NO_ERROR;
496}
497
498}
499