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