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 #include "stream_tunnel.h"
16 #include "buffer_adapter.h"
17 #include "image_buffer.h"
18
19 namespace {
20 constexpr uint32_t REQUEST_TIMEOUT = 0;
21 constexpr uint32_t STRIDE_ALIGNMENT = 8;
22 } // namespace
23
24 namespace OHOS::Camera {
~StreamTunnel()25 StreamTunnel::~StreamTunnel()
26 {
27 CAMERA_LOGV("enter");
28 DetachBufferQueue();
29 }
30
AttachBufferQueue(OHOS::sptr<OHOS::IBufferProducer> & producer)31 RetCode StreamTunnel::AttachBufferQueue(OHOS::sptr<OHOS::IBufferProducer>& producer)
32 {
33 CHECK_IF_PTR_NULL_RETURN_VALUE(producer, RC_ERROR);
34 bufferQueue_ = OHOS::Surface::CreateSurfaceAsProducer(producer);
35 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
36 return RC_OK;
37 }
38
DetachBufferQueue()39 RetCode StreamTunnel::DetachBufferQueue()
40 {
41 bufferQueue_ = nullptr;
42 return RC_OK;
43 }
44
CleanBuffers()45 void StreamTunnel::CleanBuffers()
46 {
47 if (stop_ == false) {
48 return;
49 }
50 wakeup_ = true;
51 waitCV_.notify_one();
52
53 std::lock_guard<std::mutex> l(lock_);
54 buffers.clear();
55 bufferQueue_->CleanCache();
56 index = -1;
57 }
58
GetBuffer()59 std::shared_ptr<IBuffer> StreamTunnel::GetBuffer()
60 {
61 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, nullptr);
62 OHOS::sptr<OHOS::SurfaceBuffer> sb = nullptr;
63 int32_t fence = 0;
64 OHOS::SurfaceError sfError = OHOS::SURFACE_ERROR_OK;
65 do {
66 sfError = bufferQueue_->RequestBuffer(sb, fence, requestConfig_);
67 if (sfError == OHOS::SURFACE_ERROR_NO_BUFFER) {
68 std::unique_lock<std::mutex> l(waitLock_);
69 waitCV_.wait(l, [this] { return wakeup_ == true; });
70 }
71 } while (!stop_ && sfError == OHOS::SURFACE_ERROR_NO_BUFFER);
72 wakeup_ = false;
73
74 if (stop_) {
75 if (sb != nullptr) {
76 bufferQueue_->CancelBuffer(sb);
77 }
78 return nullptr;
79 }
80
81 if (sfError != OHOS::SURFACE_ERROR_OK) {
82 CAMERA_LOGE("get producer buffer failed, error:%{public}s", SurfaceErrorStr(sfError).c_str());
83 return nullptr;
84 }
85
86 std::shared_ptr<IBuffer> cb = nullptr;
87 {
88 std::lock_guard<std::mutex> l(lock_);
89 for (auto it = buffers.begin(); it != buffers.end(); it++) {
90 if (it->second == sb) {
91 cb = it->first;
92 }
93 }
94 }
95 if (cb == nullptr) {
96 cb = std::make_shared<ImageBuffer>(CAMERA_BUFFER_SOURCE_TYPE_EXTERNAL);
97 RetCode rc = BufferAdapter::SurfaceBufferToCameraBuffer(sb, cb);
98 if (rc != RC_OK || cb == nullptr) {
99 CAMERA_LOGE("create tunnel buffer failed.");
100 return nullptr;
101 }
102
103 cb->SetIndex(++index);
104 {
105 std::lock_guard<std::mutex> l(lock_);
106 buffers[cb] = sb;
107 }
108 } else {
109 cb->SetBufferStatus(CAMERA_BUFFER_STATUS_OK);
110 }
111 restBuffers++;
112 return cb;
113 }
114
PutBuffer(const std::shared_ptr<IBuffer> & buffer)115 RetCode StreamTunnel::PutBuffer(const std::shared_ptr<IBuffer>& buffer)
116 {
117 CHECK_IF_PTR_NULL_RETURN_VALUE(buffer, RC_ERROR);
118 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
119 OHOS::sptr<OHOS::SurfaceBuffer> sb = nullptr;
120 {
121 std::lock_guard<std::mutex> l(lock_);
122 auto it = buffers.find(buffer);
123 if (it == buffers.end()) {
124 CAMERA_LOGE("buffer [%{public}d] doesn't belong to this tunnel.", buffer->GetIndex());
125 return RC_ERROR;
126 }
127 sb = it->second;
128 }
129
130 if (buffer->GetBufferStatus() == CAMERA_BUFFER_STATUS_OK) {
131 int32_t fence = 0;
132 EsFrmaeInfo esInfo = buffer->GetEsFrameInfo();
133 if (esInfo.size != -1 && esInfo.timestamp != -1) {
134 sb->ExtraSet("dataSize", esInfo.size);
135 sb->ExtraSet("isKeyFrame", esInfo.isKey);
136 sb->ExtraSet("timeStamp", esInfo.timestamp);
137 sb->ExtraSet("frameNum", esInfo.frameNum);
138 }
139 bufferQueue_->FlushBuffer(sb, fence, flushConfig_);
140 frameCount_++;
141 } else {
142 bufferQueue_->CancelBuffer(sb);
143 }
144
145 {
146 restBuffers--;
147 std::unique_lock<std::mutex> l(finishLock_);
148 finishCV_.notify_all();
149 }
150 {
151 std::unique_lock<std::mutex> l(waitLock_);
152 wakeup_ = true;
153 waitCV_.notify_one();
154 }
155 return RC_OK;
156 }
157
SetBufferCount(const int32_t n)158 RetCode StreamTunnel::SetBufferCount(const int32_t n)
159 {
160 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
161 bufferQueue_->SetQueueSize(n);
162 return RC_OK;
163 }
164
Config(const TunnelConfig config)165 RetCode StreamTunnel::Config(const TunnelConfig config)
166 {
167 requestConfig_.width = config.width;
168 requestConfig_.height = config.height;
169 requestConfig_.format = BufferAdapter::CameraFormatToPixelFormat(config.format);
170 requestConfig_.usage = BufferAdapter::CameraUsageToGrallocUsage(config.usage);
171 requestConfig_.strideAlignment = STRIDE_ALIGNMENT;
172 requestConfig_.timeout = REQUEST_TIMEOUT;
173
174 flushConfig_.damage.w = config.width;
175 flushConfig_.damage.h = config.height;
176
177 return RC_OK;
178 }
179
GetFrameCount() const180 uint64_t StreamTunnel::GetFrameCount() const
181 {
182 return frameCount_;
183 }
184
NotifyStop()185 void StreamTunnel::NotifyStop()
186 {
187 std::unique_lock<std::mutex> l(waitLock_);
188 wakeup_ = true;
189 stop_ = true;
190 waitCV_.notify_one();
191 }
192
NotifyStart()193 void StreamTunnel::NotifyStart()
194 {
195 stop_ = false;
196 }
197
WaitForAllBufferReturned()198 void StreamTunnel::WaitForAllBufferReturned()
199 {
200 std::unique_lock<std::mutex> l(finishLock_);
201 finishCV_.wait(l, [this] {
202 return restBuffers == 0;
203 });
204
205 return;
206 }
207 } // namespace OHOS::Camera
208