• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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