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
20 namespace {
21 constexpr uint32_t STRIDE_ALIGNMENT = 8;
22 } // namespace
23
24 namespace OHOS::Camera {
~StreamTunnel()25 StreamTunnel::~StreamTunnel()
26 {
27 CAMERA_LOGV("enter");
28 DetachBufferQueue();
29 }
30
AttachBufferQueue(std::shared_ptr<OHOS::Surface> & producer)31 RetCode StreamTunnel::AttachBufferQueue(std::shared_ptr<OHOS::Surface>& producer)
32 {
33 CHECK_IF_PTR_NULL_RETURN_VALUE(producer, RC_ERROR);
34 bufferQueue_ = producer;
35 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
36 return RC_OK;
37 }
38
DetachBufferQueue()39 RetCode StreamTunnel::DetachBufferQueue()
40 {
41 bufferQueue_ = nullptr;
42 return RC_OK;
43 }
44
CleanBuffers()45 void StreamTunnel::CleanBuffers()
46 {
47 if (stop_ == false) {
48 return;
49 }
50 wakeup_ = true;
51 waitCV_.notify_one();
52
53 std::lock_guard<std::mutex> l(lock_);
54 buffers.clear();
55 index = -1;
56 }
57
GetBuffer()58 std::shared_ptr<IBuffer> StreamTunnel::GetBuffer()
59 {
60 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, nullptr);
61 OHOS::SurfaceBuffer *sb = nullptr;
62 do {
63 sb = bufferQueue_->RequestBuffer();
64 if (sb == nullptr) {
65 std::unique_lock<std::mutex> l(waitLock_);
66 waitCV_.wait(l, [this] { return wakeup_ == true; });
67 }
68 } while (!stop_ && sb == nullptr);
69 wakeup_ = false;
70
71 if (stop_) {
72 if (sb != nullptr) {
73 bufferQueue_->CancelBuffer(sb);
74 }
75 return nullptr;
76 }
77
78 std::shared_ptr<IBuffer> cb = nullptr;
79 {
80 std::lock_guard<std::mutex> l(lock_);
81 for (auto it = buffers.begin(); it != buffers.end(); it++) {
82 if (it->second == sb) {
83 cb = it->first;
84 }
85 }
86 }
87 if (cb == nullptr) {
88 cb = std::make_shared<ImageBuffer>(CAMERA_BUFFER_SOURCE_TYPE_EXTERNAL);
89 RetCode rc = BufferAdapter::SurfaceBufferToCameraBuffer(sb, bufferQueue_, cb);
90 if (rc != RC_OK || cb == nullptr) {
91 CAMERA_LOGE("create tunnel buffer failed.");
92 return nullptr;
93 }
94
95 cb->SetIndex(++index);
96 {
97 std::lock_guard<std::mutex> l(lock_);
98 buffers[cb] = sb;
99 }
100 } else {
101 cb->SetBufferStatus(CAMERA_BUFFER_STATUS_OK);
102 }
103 restBuffers++;
104 return cb;
105 }
106
PutBuffer(const std::shared_ptr<IBuffer> & buffer)107 RetCode StreamTunnel::PutBuffer(const std::shared_ptr<IBuffer>& buffer)
108 {
109 CHECK_IF_PTR_NULL_RETURN_VALUE(buffer, RC_ERROR);
110 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
111 OHOS::SurfaceBuffer *sb = nullptr;
112 {
113 std::lock_guard<std::mutex> l(lock_);
114 auto it = buffers.find(buffer);
115 if (it == buffers.end()) {
116 CAMERA_LOGE("buffer [%{public}d] doesn't belong to this tunnel.", buffer->GetIndex());
117 return RC_ERROR;
118 }
119 sb = it->second;
120 }
121
122 if (buffer->GetBufferStatus() == CAMERA_BUFFER_STATUS_OK) {
123 EsFrameInfo esInfo = buffer->GetEsFrameInfo();
124 if (esInfo.size != -1 && esInfo.timestamp != -1) {
125 sb->SetInt32(OHOS::Camera::VIDEO_KEY_INFO_DATA_SIZE, esInfo.size);
126 sb->SetInt32(OHOS::Camera::VIDEO_KEY_INFO_IS_KEY_FRAME, esInfo.isKey);
127 sb->SetInt64(OHOS::Camera::VIDEO_KEY_INFO_TIMESTAMP, esInfo.timestamp);
128 }
129 bufferQueue_->FlushBuffer(sb);
130 frameCount_++;
131 } else {
132 bufferQueue_->CancelBuffer(sb);
133 }
134
135 {
136 restBuffers--;
137 std::unique_lock<std::mutex> l(finishLock_);
138 finishCV_.notify_all();
139 }
140 {
141 std::unique_lock<std::mutex> l(waitLock_);
142 wakeup_ = true;
143 waitCV_.notify_one();
144 }
145 return RC_OK;
146 }
147
SetBufferCount(const int32_t n)148 RetCode StreamTunnel::SetBufferCount(const int32_t n)
149 {
150 CHECK_IF_PTR_NULL_RETURN_VALUE(bufferQueue_, RC_ERROR);
151 bufferQueue_->SetQueueSize(n);
152 return RC_OK;
153 }
154
Config(const TunnelConfig & config)155 RetCode StreamTunnel::Config(const TunnelConfig& config)
156 {
157 bufferQueue_->SetWidthAndHeight(config.width, config.height);
158 bufferQueue_->SetFormat(BufferAdapter::CameraFormatToPixelFormat(config.format));
159 bufferQueue_->SetStrideAlignment(STRIDE_ALIGNMENT);
160
161 return RC_OK;
162 }
163
GetFrameCount() const164 uint64_t StreamTunnel::GetFrameCount() const
165 {
166 return frameCount_;
167 }
168
NotifyStop()169 void StreamTunnel::NotifyStop()
170 {
171 std::unique_lock<std::mutex> l(waitLock_);
172 wakeup_ = true;
173 stop_ = true;
174 waitCV_.notify_one();
175 }
176
NotifyStart()177 void StreamTunnel::NotifyStart()
178 {
179 stop_ = false;
180 }
181
WaitForAllBufferReturned()182 void StreamTunnel::WaitForAllBufferReturned()
183 {
184 std::unique_lock<std::mutex> l(finishLock_);
185 finishCV_.wait(l, [this] {
186 return restBuffers == 0;
187 });
188
189 return;
190 }
191 } // namespace OHOS::Camera
192