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 "surface_reader.h"
17#include "sync_fence.h"
18#include "window_manager_hilog.h"
19#include "unique_fd.h"
20
21#include <securec.h>
22
23using namespace OHOS::Media;
24
25namespace OHOS {
26namespace Rosen {
27namespace {
28constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "SurfaceReader"};
29} // namespace
30const int BPP = 4; // bytes per pixel
31
32SurfaceReader::SurfaceReader()
33{
34}
35
36SurfaceReader::~SurfaceReader()
37{
38    if (csurface_ != nullptr) {
39        csurface_->UnregisterConsumerListener();
40    }
41    psurface_ = nullptr;
42    csurface_ = nullptr;
43}
44
45bool SurfaceReader::Init()
46{
47    csurface_ = IConsumerSurface::Create();
48    if (csurface_ == nullptr) {
49        return false;
50    }
51
52    auto producer = csurface_->GetProducer();
53    psurface_ = Surface::CreateSurfaceAsProducer(producer);
54    if (psurface_ == nullptr) {
55        return false;
56    }
57
58    listener_ = new BufferListener(*this);
59    SurfaceError ret = csurface_->RegisterConsumerListener(listener_);
60    if (ret != SURFACE_ERROR_OK) {
61        return false;
62    }
63    return true;
64}
65
66void SurfaceReader::OnVsync()
67{
68    WLOGI("SurfaceReader::OnVsync");
69
70    sptr<SurfaceBuffer> cbuffer = nullptr;
71    int32_t fence = -1;
72    int64_t timestamp = 0;
73    Rect damage;
74    auto sret = csurface_->AcquireBuffer(cbuffer, fence, timestamp, damage);
75    sptr<SyncFence> acquireFence = new SyncFence(fence);
76    acquireFence->Wait(3000); // 3000ms
77    if (cbuffer == nullptr || sret != OHOS::SURFACE_ERROR_OK) {
78        WLOGFE("SurfaceReader::OnVsync: surface buffer is null");
79        return;
80    }
81
82    if (!ProcessBuffer(cbuffer)) {
83        WLOGFE("SurfaceReader::OnVsync: ProcessBuffer failed");
84        return;
85    }
86
87    if (cbuffer != prevBuffer_) {
88        if (prevBuffer_ != nullptr) {
89            SurfaceError ret = csurface_->ReleaseBuffer(prevBuffer_, -1);
90            if (ret != SURFACE_ERROR_OK) {
91                WLOGFE("SurfaceReader::OnVsync: release buffer error");
92                return;
93            }
94        }
95
96        prevBuffer_ = cbuffer;
97    }
98}
99
100sptr<Surface> SurfaceReader::GetSurface() const
101{
102    return psurface_;
103}
104
105void SurfaceReader::SetHandler(sptr<SurfaceReaderHandler> handler)
106{
107    handler_ = handler;
108}
109
110bool SurfaceReader::ProcessBuffer(const sptr<SurfaceBuffer>& buf)
111{
112    if (handler_ == nullptr) {
113        WLOGFE("SurfaceReaderHandler not set");
114        return false;
115    }
116
117    BufferHandle *bufferHandle =  buf->GetBufferHandle();
118    if (bufferHandle == nullptr) {
119        WLOGFE("bufferHandle nullptr");
120        return false;
121    }
122
123    uint32_t width = static_cast<uint32_t>(bufferHandle->width);
124    uint32_t height = static_cast<uint32_t>(bufferHandle->height);
125    uint32_t stride = static_cast<uint32_t>(bufferHandle->stride);
126    uint8_t *addr = (uint8_t *)buf->GetVirAddr();
127
128    auto data = (uint8_t *)malloc(width * height * BPP);
129    if (data == nullptr) {
130        WLOGFE("data malloc failed");
131        return false;
132    }
133    for (uint32_t i = 0; i < height; i++) {
134        errno_t ret = memcpy_s(data + width * i * BPP,  width * BPP, addr + stride * i, width * BPP);
135        if (ret != EOK) {
136            WLOGFE("memcpy failed");
137            free(data);
138            return false;
139        }
140    }
141
142    Media::InitializationOptions opts;
143    opts.size.width = static_cast<int32_t>(width);
144    opts.size.height = static_cast<int32_t>(height);
145    std::unique_ptr<Media::PixelMap> pixelMapPtr = Media::PixelMap::Create(opts);
146    sptr<Media::PixelMap> pixelMap(pixelMapPtr.release());
147    if (pixelMap == nullptr) {
148        WLOGFE("create pixelMap failed");
149        free(data);
150        return false;
151    }
152
153    ImageInfo info;
154    info.size.width = static_cast<int32_t>(width);
155    info.size.height = static_cast<int32_t>(height);
156    info.pixelFormat = OHOS::Media::PixelFormat::RGBA_8888;
157    info.colorSpace = ColorSpace::SRGB;
158    pixelMap->SetImageInfo(info);
159
160    pixelMap->SetPixelsAddr(data, nullptr, width * height, AllocatorType::HEAP_ALLOC, nullptr);
161
162    handler_->OnImageAvailable(pixelMap);
163    return true;
164}
165}
166}
167