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