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 #include "video_key_info.h"
19 #include "camera_dump.h"
20 #include "camera_hal_hisysevent.h"
21
22 namespace {
23 constexpr uint32_t REQUEST_TIMEOUT = 0;
24 constexpr uint32_t STRIDE_ALIGNMENT = 8;
25 } // namespace
26
27 namespace OHOS::Camera {
~StreamTunnel()28 StreamTunnel::~StreamTunnel()
29 {
30 CAMERA_LOGV("enter");
31 DetachBufferQueue();
32 }
33
AttachBufferQueue(OHOS::sptr<OHOS::IBufferProducer> & producer)34 RetCode StreamTunnel::AttachBufferQueue(OHOS::sptr<OHOS::IBufferProducer>& producer)
35 {
36 CHECK_IF_PTR_NULL_RETURN_VALUE(producer, RC_ERROR);
37 bufferQueue_ = OHOS::Surface::CreateSurfaceAsProducer(producer);
38 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
39 return RC_OK;
40 }
41
DetachBufferQueue()42 RetCode StreamTunnel::DetachBufferQueue()
43 {
44 bufferQueue_ = nullptr;
45 return RC_OK;
46 }
47
CleanBuffers()48 void StreamTunnel::CleanBuffers()
49 {
50 if (stop_ == false) {
51 return;
52 }
53 wakeup_ = true;
54 waitCV_.notify_one();
55
56 std::lock_guard<std::mutex> l(lock_);
57 buffers.clear();
58 bufferQueue_->CleanCache();
59 index = -1;
60 }
61
GetBuffer()62 std::shared_ptr<IBuffer> StreamTunnel::GetBuffer()
63 {
64 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, nullptr);
65 OHOS::sptr<OHOS::SurfaceBuffer> sb = nullptr;
66 int32_t fence = 0;
67 constexpr int32_t SLEEP_TIME = 2000;
68 int32_t timtCount = 0;
69 OHOS::SurfaceError sfError = OHOS::SURFACE_ERROR_OK;
70 do {
71 sfError = bufferQueue_->RequestBuffer(sb, fence, requestConfig_);
72 if (sfError == OHOS::SURFACE_ERROR_NO_BUFFER) {
73 std::unique_lock<std::mutex> l(waitLock_);
74 waitCV_.wait(l, [this] { return wakeup_ == true; });
75 usleep(SLEEP_TIME);
76 timtCount++;
77 }
78 if (fence != -1) {
79 close(fence);
80 }
81 stats_.RequestBufferResult(sfError);
82 } while (!stop_ && sfError == OHOS::SURFACE_ERROR_NO_BUFFER);
83 wakeup_ = false;
84 CAMERA_LOGE("bufferQueue_->RequestBuffer Done, sfError = %{public}d, cast time = %{public}d us",
85 sfError, timtCount * SLEEP_TIME);
86
87 if (stop_) {
88 if (sb != nullptr) {
89 int ret = bufferQueue_->CancelBuffer(sb);
90 stats_.CancelBufferResult(ret);
91 }
92 return nullptr;
93 }
94
95 if (sfError != OHOS::SURFACE_ERROR_OK) {
96 CAMERA_LOGE("get producer buffer failed, error:%{public}s", SurfaceErrorStr(sfError).c_str());
97 CameraHalHisysevent::WriteFaultHisysEvent(CameraHalHisysevent::GetEventName(REQUEST_GRAPHIC_BUFFER_ERROR),
98 CameraHalHisysevent::CreateMsg("request graphic buffer failed rc:%s", SurfaceErrorStr(sfError).c_str()));
99 return nullptr;
100 }
101
102 std::shared_ptr<IBuffer> cb = GetCameraBufferAndUpdateInfo(sb);
103 restBuffers.fetch_add(1, std::memory_order_release);
104 return cb;
105 }
106
PrepareBufferBeforeFlush(const std::shared_ptr<IBuffer> & buffer,const OHOS::sptr<OHOS::SurfaceBuffer> & sb)107 static void PrepareBufferBeforeFlush(const std::shared_ptr<IBuffer>& buffer, const OHOS::sptr<OHOS::SurfaceBuffer> &sb)
108 {
109 EsFrameInfo esInfo = buffer->GetEsFrameInfo();
110 if (esInfo.size != -1) {
111 const sptr<OHOS::BufferExtraData>& extraData = sb->GetExtraData();
112 if (extraData != nullptr) {
113 extraData->ExtraSet(OHOS::Camera::dataSize, esInfo.size);
114 extraData->ExtraSet(OHOS::Camera::isKeyFrame, esInfo.isKey);
115 extraData->ExtraSet(OHOS::Camera::timeStamp, esInfo.timestamp);
116 extraData->ExtraSet(OHOS::Camera::streamId, buffer->GetStreamId());
117 extraData->ExtraSet(OHOS::Camera::captureId, buffer->GetCaptureId());
118 }
119 }
120 if (!buffer->GetIsValidDataInSurfaceBuffer()) {
121 CAMERA_LOGI("copy data from cb to sb, size = %{public}d", sb->GetSize());
122 auto ret = memcpy_s(sb->GetVirAddr(), sb->GetSize(), buffer->GetVirAddress(), sb->GetSize());
123 if (ret != 0) {
124 CAMERA_LOGE("PrepareBufferBeforeFlush memcpy_s fail, error = %{public}d", ret);
125 }
126 }
127 buffer->SetIsValidDataInSurfaceBuffer(false);
128 }
129
PutBuffer(const std::shared_ptr<IBuffer> & buffer)130 RetCode StreamTunnel::PutBuffer(const std::shared_ptr<IBuffer>& buffer)
131 {
132 CHECK_IF_PTR_NULL_RETURN_VALUE(buffer, RC_ERROR);
133 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
134 OHOS::sptr<OHOS::SurfaceBuffer> sb = nullptr;
135 {
136 std::lock_guard<std::mutex> l(lock_);
137 auto it = buffers.find(buffer);
138 if (it == buffers.end()) {
139 CAMERA_LOGE("buffer [%{public}d] doesn't belong to this tunnel.", buffer->GetIndex());
140 return RC_ERROR;
141 }
142 sb = it->second;
143 }
144
145 if (buffer->GetBufferStatus() == CAMERA_BUFFER_STATUS_OK) {
146 CAMERAHALPERFSYSEVENT_EQUAL(0, frameCount_, TIME_FOR_FIRST_FRAME);
147 CameraDumper& dumper = CameraDumper::GetInstance();
148 dumper.DumpBuffer("BeforeFlushSurface", ENABLE_STREAM_TUNNEL, buffer,
149 buffer->GetCurWidth(), buffer->GetCurHeight());
150 PrepareBufferBeforeFlush(buffer, sb);
151 int64_t timestamp = 0;
152 sb->GetExtraData()->ExtraGet(OHOS::Camera::timeStamp, timestamp);
153 flushConfig_.timestamp = timestamp;
154 int32_t fence = -1;
155 int ret = bufferQueue_->FlushBuffer(sb, fence, flushConfig_);
156 CAMERA_LOGI("FlushBuffer stream = [%{public}d], timestamp = [%{public}d], ret = [%{public}d]",
157 buffer->GetStreamId(), timestamp, ret);
158 stats_.FlushBufferResult(ret);
159 frameCount_++;
160 } else {
161 int ret = bufferQueue_->CancelBuffer(sb);
162 CAMERA_LOGI("CancelBuffer done, streamId = %{public}d, index = %{public}d, ret = %{public}d",
163 buffer->GetStreamId(), buffer->GetIndex(), ret);
164 stats_.CancelBufferResult(ret);
165 }
166
167 restBuffers.fetch_sub(1, std::memory_order_release);
168 finishCV_.notify_all();
169 {
170 std::unique_lock<std::mutex> l(waitLock_);
171 wakeup_ = true;
172 waitCV_.notify_one();
173 }
174 return RC_OK;
175 }
176
SetBufferCount(const int32_t n)177 RetCode StreamTunnel::SetBufferCount(const int32_t n)
178 {
179 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
180 bufferQueue_->SetQueueSize(n);
181 return RC_OK;
182 }
183
Config(const TunnelConfig & config)184 RetCode StreamTunnel::Config(const TunnelConfig& config)
185 {
186 requestConfig_.width = config.width;
187 requestConfig_.height = config.height;
188 requestConfig_.format = BufferAdapter::CameraFormatToPixelFormat(config.format);
189 requestConfig_.usage = BufferAdapter::CameraUsageToGrallocUsage(config.usage);
190 requestConfig_.strideAlignment = STRIDE_ALIGNMENT;
191 requestConfig_.timeout = REQUEST_TIMEOUT;
192
193 flushConfig_.damage.w = config.width;
194 flushConfig_.damage.h = config.height;
195
196 return RC_OK;
197 }
198
GetFrameCount() const199 uint64_t StreamTunnel::GetFrameCount() const
200 {
201 return frameCount_;
202 }
203
NotifyStop()204 void StreamTunnel::NotifyStop()
205 {
206 std::unique_lock<std::mutex> l(waitLock_);
207 wakeup_ = true;
208 stop_ = true;
209 waitCV_.notify_one();
210 }
211
NotifyStart()212 void StreamTunnel::NotifyStart()
213 {
214 stop_ = false;
215 }
216
WaitForAllBufferReturned()217 void StreamTunnel::WaitForAllBufferReturned()
218 {
219 std::unique_lock<std::mutex> l(finishLock_);
220 auto timeout = std::chrono::system_clock::now() + std::chrono::microseconds(1000 * 300); // 200ms
221 if (!finishCV_.wait_until(l, timeout, [this] {
222 CAMERA_LOGD("restBuffers=%{public}u", restBuffers.load(std::memory_order_acquire));
223 return restBuffers.load(std::memory_order_acquire) == 0;
224 })) {
225 CAMERA_LOGW(
226 "WaitForAllBufferReturned timeout, restBuffers=%{public}u", restBuffers.load(std::memory_order_acquire));
227 } else {
228 CAMERA_LOGW(
229 "WaitForAllBufferReturned done, restBuffers=%{public}u", restBuffers.load(std::memory_order_acquire));
230 }
231 }
232
DumpStats(int interval)233 void StreamTunnel::DumpStats(int interval)
234 {
235 stats_.DumpStats(interval);
236 }
237
SetStreamId(int32_t streamId)238 void StreamTunnel::SetStreamId(int32_t streamId)
239 {
240 streamId_ = streamId;
241 stats_.SetStreamId(streamId);
242 }
243
GetCameraBufferAndUpdateInfo(OHOS::sptr<OHOS::SurfaceBuffer> sb)244 std::shared_ptr<IBuffer> StreamTunnel::GetCameraBufferAndUpdateInfo(OHOS::sptr<OHOS::SurfaceBuffer> sb)
245 {
246 std::shared_ptr<IBuffer> cb = nullptr;
247 {
248 std::lock_guard<std::mutex> l(lock_);
249 for (auto it = buffers.begin(); it != buffers.end(); it++) {
250 if (it->second == sb) {
251 cb = it->first;
252 CAMERA_LOGD("GetCameraBufferAndUpdateInfo, found sb in buffers");
253 }
254 }
255 }
256 if (cb == nullptr) {
257 cb = std::make_shared<ImageBuffer>(CAMERA_BUFFER_SOURCE_TYPE_EXTERNAL);
258 RetCode rc = BufferAdapter::SurfaceBufferToCameraBuffer(sb, cb);
259 if (rc != RC_OK || cb == nullptr) {
260 CameraHalHisysevent::WriteFaultHisysEvent(CameraHalHisysevent::GetEventName(TURN_BUFFER_ERROR),
261 CameraHalHisysevent::CreateMsg("graphic buffer transfor camera buffer failed rc:%d", rc));
262 CAMERA_LOGE("create tunnel buffer failed.");
263 return nullptr;
264 }
265
266 cb->SetIndex(++index);
267 {
268 std::lock_guard<std::mutex> l(lock_);
269 buffers[cb] = sb;
270 }
271 CAMERA_LOGD("GetCameraBufferAndUpdateInfo, create ImageBuffer. index = %{public}d", cb->GetIndex());
272 } else {
273 cb->SetBufferStatus(CAMERA_BUFFER_STATUS_OK);
274 }
275 return cb;
276 }
277 } // namespace OHOS::Camera
278