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