1 /*
2 * Copyright (C) 2021–2022 Beijing OSWare Technology Co., Ltd
3 * This file contains confidential and proprietary information of
4 * OSWare Technology Co., Ltd
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include <cerrno>
20 #include <cstdio>
21 #include <string>
22 #include "v4l2_buffer.h"
23 namespace OHOS::Camera {
HosV4L2Buffers(enum v4l2_memory memType,enum v4l2_buf_type bufferType)24 HosV4L2Buffers::HosV4L2Buffers(enum v4l2_memory memType, enum v4l2_buf_type bufferType)
25 : memoryType_(memType), bufferType_(bufferType)
26 {
27 additional_info_ = Imx8mmImageAdditionalInfo::GetInstance();
28 }
29
~HosV4L2Buffers()30 HosV4L2Buffers::~HosV4L2Buffers()
31 {
32 delete(additional_info_);
33 }
34
V4L2ReqBuffers(int fd,int unsigned buffCont)35 RetCode HosV4L2Buffers::V4L2ReqBuffers(int fd, int unsigned buffCont)
36 {
37 struct v4l2_requestbuffers req = {};
38
39 CAMERA_LOGD("V4L2ReqBuffers buffCont %d\n", buffCont);
40
41 req.count = buffCont;
42 req.type = bufferType_;
43 req.memory = memoryType_;
44 adapterBufferList = (struct AdapterBuffer*)calloc(req.count, sizeof(struct AdapterBuffer));
45
46 if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
47 CAMERA_LOGE("does not support memory mapping %s\n", strerror(errno));
48 return RC_ERROR;
49 }
50
51 if (req.count != buffCont) {
52 CAMERA_LOGE("error Insufficient buffer memory on \n");
53
54 req.count = 0;
55 req.type = bufferType_;
56 req.memory = memoryType_;
57 if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
58 CAMERA_LOGE("V4L2ReqBuffers does not release buffer %s\n", strerror(errno));
59 return RC_ERROR;
60 }
61
62 return RC_ERROR;
63 }
64
65 return RC_OK;
66 }
67
V4L2QueueBuffer(int fd,const std::shared_ptr<FrameSpec> & frameSpec)68 RetCode HosV4L2Buffers::V4L2QueueBuffer(int fd, const std::shared_ptr<FrameSpec>& frameSpec)
69 {
70 struct v4l2_buffer buf = {};
71 struct v4l2_plane planes[1] = {};
72
73 if (frameSpec == nullptr) {
74 CAMERA_LOGE("V4L2QueueBuffer: frameSpec is NULL\n");
75 return RC_ERROR;
76 }
77
78 uint32_t index = (uint32_t)frameSpec->buffer_->GetIndex();
79 adapterBufferList[index].userBufPtr = frameSpec->buffer_->GetVirAddress();
80 adapterBufferList[index].length = additional_info_->GetLength();
81
82 buf.index = (uint32_t)frameSpec->buffer_->GetIndex();
83 buf.type = bufferType_;
84 buf.memory = memoryType_;
85
86 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
87 buf.m.planes = planes;
88 buf.m.planes[0].length = frameSpec->buffer_->GetSize();
89 buf.m.planes[0].m.userptr = (unsigned long)frameSpec->buffer_->GetVirAddress();
90 buf.length = 1;
91
92 CAMERA_LOGD("++++++++++++ V4L2QueueBuffer buf.index = %{public}d, buf.length = \
93 %{public}d, buf.m.userptr = %{public}p\n", \
94 buf.index, buf.m.planes[0].length, (void*)buf.m.planes[0].m.userptr);
95 } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
96 switch (memoryType_) {
97 case V4L2_MEMORY_MMAP:
98 {
99 adapterBufferList[index].start = mmap(NULL, additional_info_->GetLength(),
100 PROT_READ | PROT_WRITE, MAP_SHARED, fd, additional_info_->GetOffset());
101 if (MAP_FAILED == adapterBufferList[index].start) {
102 CAMERA_LOGE("v4l2 mmap failed\n");
103 return RC_ERROR;
104 }
105 CAMERA_LOGD("++++++++++++ V4L2QueueBuffer buf.index = %{public}d, buf.length = \
106 %{public}d, adapterBufferList[%{public}d].start = %{public}p\n", \
107 buf.index, buf.length, index, (void*)adapterBufferList[index].start);
108
109 break;
110 }
111 case V4L2_MEMORY_USERPTR:
112 {
113 buf.length = frameSpec->buffer_->GetSize();
114 buf.m.userptr = (unsigned long)frameSpec->buffer_->GetVirAddress();
115
116 CAMERA_LOGD("++++++++++++ V4L2QueueBuffer buf.index = %{public}d, buf.length = \
117 %{public}d, buf.m.userptr = %{public}p\n", \
118 buf.index, buf.length, (void*)buf.m.userptr);
119 break;
120 }
121 default:
122 CAMERA_LOGE("It can not be happening - incorrect memory type\n");
123 return RC_ERROR;
124 }
125 }
126
127 std::lock_guard<std::mutex> l(bufferLock_);
128 int rc = ioctl(fd, VIDIOC_QBUF, &buf);
129 if (rc < 0) {
130 CAMERA_LOGE("ioctl VIDIOC_QBUF failed: %s\n", strerror(errno));
131 return RC_ERROR;
132 }
133
134 auto itr = queueBuffers_.find(fd);
135 if (itr != queueBuffers_.end()) {
136 itr->second[buf.index] = frameSpec;
137 CAMERA_LOGD("insert frameMap fd = %{public}d buf.index = %{public}d\n", fd, buf.index);
138 } else {
139 FrameMap frameMap;
140 frameMap.insert(std::make_pair(buf.index, frameSpec));
141 queueBuffers_.insert(std::make_pair(fd, frameMap));
142 CAMERA_LOGD("insert fd = %{public}d buf.index = %{public}d\n", fd, buf.index);
143 }
144
145 return RC_OK;
146 }
147
V4L2DequeueBuffer(int fd)148 RetCode HosV4L2Buffers::V4L2DequeueBuffer(int fd)
149 {
150 struct v4l2_buffer buf = {};
151 struct v4l2_plane planes[1] = {};
152
153 buf.type = bufferType_;
154 buf.memory = memoryType_;
155
156 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
157 buf.m.planes = planes;
158 buf.length = 1;
159 }
160 int rc = ioctl(fd, VIDIOC_DQBUF, &buf);
161 if (rc < 0) {
162 CAMERA_LOGE("ioctl VIDIOC_DQBUF failed: %s\n", strerror(errno));
163 return RC_ERROR;
164 }
165
166 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
167 CAMERA_LOGD("---------------- V4L2DequeueBuffer index = %{public}d buf.m.ptr = %{public}p len = %{public}d\n",
168 buf.index, (void*)buf.m.planes[0].m.userptr, buf.m.planes[0].length);
169 } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
170 CAMERA_LOGD("---------------- V4L2DequeueBuffer index = %{public}d buf.m.ptr = %{public}p len = %{public}d\n",
171 buf.index, (void*)buf.m.userptr, buf.length);
172 }
173
174 if (memoryType_ == V4L2_MEMORY_MMAP) {
175 memcpy(adapterBufferList[buf.index].userBufPtr,
176 adapterBufferList[buf.index].start, adapterBufferList[buf.index].length);
177
178 if (munmap(adapterBufferList[buf.index].start, adapterBufferList[buf.index].length) < 0) {
179 CAMERA_LOGE("munmap is fail\n");
180 return RC_ERROR;
181 }
182 }
183
184 auto IterMap = queueBuffers_.find(fd);
185 if (IterMap == queueBuffers_.end()) {
186 CAMERA_LOGE("std::map queueBuffers_ no fd\n");
187 return RC_ERROR;
188 }
189 auto& bufferMap = IterMap->second;
190
191 auto Iter = bufferMap.find(buf.index);
192 if (Iter == bufferMap.end()) {
193 CAMERA_LOGE("V4L2DequeueBuffer buf.index == %{public}d is not find in FrameMap\n", buf.index);
194 return RC_ERROR;
195 }
196
197 if (dequeueBuffer_ == nullptr) {
198 CAMERA_LOGE("V4L2DequeueBuffer buf.index == %{public}d no callback\n", buf.index);
199 std::lock_guard<std::mutex> l(bufferLock_);
200 bufferMap.erase(Iter);
201 return RC_ERROR;
202 }
203
204 // callback to up
205 dequeueBuffer_(Iter->second);
206 std::lock_guard<std::mutex> l(bufferLock_);
207 bufferMap.erase(Iter);
208
209 return RC_OK;
210 }
211
V4L2AllocBuffer(int fd,const std::shared_ptr<FrameSpec> & frameSpec)212 RetCode HosV4L2Buffers::V4L2AllocBuffer(int fd, const std::shared_ptr<FrameSpec>& frameSpec)
213 {
214 struct v4l2_buffer buf = {};
215 struct v4l2_plane planes[1] = {};
216 CAMERA_LOGD("V4L2AllocBuffer\n");
217
218 if (frameSpec == nullptr) {
219 CAMERA_LOGE("V4L2AllocBuffer frameSpec is NULL\n");
220 return RC_ERROR;
221 }
222
223 switch (memoryType_) {
224 case V4L2_MEMORY_MMAP:
225 case V4L2_MEMORY_USERPTR:
226 buf.type = bufferType_;
227 buf.memory = memoryType_;
228 buf.index = (uint32_t)frameSpec->buffer_->GetIndex();
229
230 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
231 buf.m.planes = planes;
232 buf.length = 1;
233 }
234 CAMERA_LOGD("V4L2_MEMORY_USERPTR Print the cnt: %{public}d\n", buf.index);
235
236 if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
237 CAMERA_LOGE("error: ioctl VIDIOC_QUERYBUF failed: %{public}s\n", strerror(errno));
238 return RC_ERROR;
239 }
240
241 CAMERA_LOGD("buf.length = %{public}d frameSpec->buffer_->GetSize() = %{public}d\n", buf.length,
242 frameSpec->buffer_->GetSize());
243
244 if (buf.length > frameSpec->buffer_->GetSize()) {
245 CAMERA_LOGE("ERROR:user buff < V4L2 buf.length\n");
246 return RC_ERROR;
247 }
248 additional_info_->SetLength(buf.length);
249 additional_info_->SetOffset(buf.m.offset);
250
251 break;
252 case V4L2_MEMORY_OVERLAY:
253 // to do something
254 break;
255
256 case V4L2_MEMORY_DMABUF:
257 // to do something
258 break;
259
260 default:
261 CAMERA_LOGE("It can not be happening - incorrect memory type\n");
262 return RC_ERROR;
263 }
264
265 return RC_OK;
266 }
267
V4L2ReleaseBuffers(int fd)268 RetCode HosV4L2Buffers::V4L2ReleaseBuffers(int fd)
269 {
270 CAMERA_LOGE("HosV4L2Buffers::V4L2ReleaseBuffers\n");
271
272 std::lock_guard<std::mutex> l(bufferLock_);
273 queueBuffers_.erase(fd);
274
275 return V4L2ReqBuffers(fd, 0);
276 }
277
SetCallback(BufCallback cb)278 void HosV4L2Buffers::SetCallback(BufCallback cb)
279 {
280 CAMERA_LOGD("HosV4L2Buffers::SetCallback OK.");
281 dequeueBuffer_ = cb;
282 }
Flush(int fd)283 RetCode HosV4L2Buffers::Flush(int fd)
284 {
285 CAMERA_LOGE("HosV4L2Buffers::Flush\n");
286 return RC_OK;
287 }
288 } // namespace OHOS::Camera
289