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
16 #include <sys/mman.h>
17 #include <unistd.h>
18 #include <linux/dma-heap.h>
19 #include <linux/dma-buf.h>
20 #ifndef V4L2_MAIN_TEST
21 #include "ibuffer.h"
22 #endif
23 #include "securec.h"
24 #include "v4l2_buffer.h"
25
26 namespace OHOS::Camera {
27 const std::string DMA_BUF_FILE_NAME = "/dev/dma_heap/system";
HosV4L2Buffers(enum v4l2_memory memType,enum v4l2_buf_type bufferType)28 HosV4L2Buffers::HosV4L2Buffers(enum v4l2_memory memType, enum v4l2_buf_type bufferType)
29 : memoryType_(memType), bufferType_(bufferType)
30 {
31 }
32
~HosV4L2Buffers()33 HosV4L2Buffers::~HosV4L2Buffers() {}
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 %{public}d\n", buffCont);
40
41 req.count = buffCont;
42 req.type = bufferType_;
43 req.memory = memoryType_;
44
45 if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
46 CAMERA_LOGE("does not support memory mapping %{public}s\n", strerror(errno));
47 return RC_ERROR;
48 }
49
50 if (req.count != buffCont) {
51 CAMERA_LOGE("error Insufficient buffer memory on \n");
52
53 req.count = 0;
54 req.type = bufferType_;
55 req.memory = memoryType_;
56 if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
57 CAMERA_LOGE("V4L2ReqBuffers does not release buffer %s\n", strerror(errno));
58 return RC_ERROR;
59 }
60
61 return RC_ERROR;
62 }
63 return RC_OK;
64 }
65
V4L2QueueBuffer(int fd,const std::shared_ptr<FrameSpec> & frameSpec)66 RetCode HosV4L2Buffers::V4L2QueueBuffer(int fd, const std::shared_ptr<FrameSpec>& frameSpec)
67 {
68 struct v4l2_buffer buf = {};
69 struct v4l2_plane planes[1] = {};
70
71 if (frameSpec == nullptr) {
72 CAMERA_LOGE("V4L2QueueBuffer: frameSpec is NULL\n");
73 return RC_ERROR;
74 }
75 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
76 buf.m.planes = planes;
77 }
78
79 MakeInqueueBuffer(buf, frameSpec);
80
81 std::lock_guard<std::mutex> l(bufferLock_);
82 int rc = ioctl(fd, VIDIOC_QBUF, &buf);
83 if (rc < 0) {
84 CAMERA_LOGE("ioctl VIDIOC_QBUF failed: %s\n", strerror(errno));
85 return RC_ERROR;
86 }
87
88 auto itr = queueBuffers_.find(fd);
89 if (itr != queueBuffers_.end()) {
90 itr->second[buf.index] = frameSpec;
91 CAMERA_LOGD("insert frameMap fd = %{public}d buf.index = %{public}d\n", fd, buf.index);
92 } else {
93 FrameMap frameMap;
94 frameMap.insert(std::make_pair(buf.index, frameSpec));
95 queueBuffers_.insert(std::make_pair(fd, frameMap));
96 CAMERA_LOGD("insert fd = %{public}d buf.index = %{public}d\n", fd, buf.index);
97 }
98
99 return RC_OK;
100 }
101
MakeInqueueBuffer(struct v4l2_buffer & buf,const std::shared_ptr<FrameSpec> & frameSpec)102 void HosV4L2Buffers::MakeInqueueBuffer(struct v4l2_buffer &buf, const std::shared_ptr<FrameSpec>& frameSpec)
103 {
104 CAMERA_LOGD("HosV4L2Buffers::MakeInqueueBuffer in.");
105
106 buf.index = (uint32_t)frameSpec->buffer_->GetIndex();
107 buf.type = bufferType_;
108 buf.memory = memoryType_;
109
110 switch (memoryType_) {
111 case V4L2_MEMORY_MMAP:
112 SetMmapInqueueBuffer(buf, frameSpec);
113 break;
114 case V4L2_MEMORY_USERPTR:
115 SetInqueueBuffer(buf, frameSpec);
116 break;
117 case V4L2_MEMORY_OVERLAY:
118 break;
119 case V4L2_MEMORY_DMABUF:
120 SetDmaInqueueBuffer(buf, frameSpec);
121 break;
122 default:
123 CAMERA_LOGE("It can not be happening - incorrect memoryType\n");
124 return;
125 }
126 return;
127 }
128
SetInqueueBuffer(struct v4l2_buffer & buf,const std::shared_ptr<FrameSpec> & frameSpec)129 void HosV4L2Buffers::SetInqueueBuffer(struct v4l2_buffer &buf, const std::shared_ptr<FrameSpec>& frameSpec)
130 {
131 CAMERA_LOGD("HosV4L2Buffers::SetInqueueBuffer in.");
132 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
133 buf.m.planes[0].length = frameSpec->buffer_->GetSize();
134 buf.m.planes[0].m.userptr = (unsigned long)frameSpec->buffer_->GetVirAddress();
135 buf.length = 1;
136 } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
137 buf.length = frameSpec->buffer_->GetSize();
138 buf.m.userptr = (unsigned long)frameSpec->buffer_->GetVirAddress();
139 }
140 return;
141 }
142
SetMmapInqueueBuffer(struct v4l2_buffer & buf,const std::shared_ptr<FrameSpec> & frameSpec)143 void HosV4L2Buffers::SetMmapInqueueBuffer(struct v4l2_buffer &buf, const std::shared_ptr<FrameSpec>& frameSpec)
144 {
145 CAMERA_LOGD("HosV4L2Buffers::SetMmapInqueueBuffer in.");
146 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
147 buf.m.planes[0].length = adapterBufferMap_[buf.index].length;
148 buf.m.planes[0].m.mem_offset = adapterBufferMap_[buf.index].offset;
149 buf.length = 1;
150 } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
151 buf.length = adapterBufferMap_[buf.index].length;
152 buf.m.offset = adapterBufferMap_[buf.index].offset;
153 }
154 return;
155 }
156
SetDmaInqueueBuffer(struct v4l2_buffer & buf,const std::shared_ptr<FrameSpec> & frameSpec)157 void HosV4L2Buffers::SetDmaInqueueBuffer(struct v4l2_buffer &buf, const std::shared_ptr<FrameSpec>& frameSpec)
158 {
159 CAMERA_LOGD("HosV4L2Buffers::SetDmaInqueueBuffer in.");
160 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
161 buf.length = 1;
162 buf.m.planes[0].length = adapterBufferMap_[buf.index].length;
163 buf.m.planes[0].m.fd = adapterBufferMap_[buf.index].dmafd;
164 } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
165 buf.length = adapterBufferMap_[buf.index].length;
166 buf.m.fd = adapterBufferMap_[buf.index].dmafd;
167 }
168 return;
169 }
170
V4L2DequeueBuffer(int fd)171 RetCode HosV4L2Buffers::V4L2DequeueBuffer(int fd)
172 {
173 struct v4l2_buffer buf = {};
174 struct v4l2_plane planes[1] = {};
175
176 buf.type = bufferType_;
177 buf.memory = memoryType_;
178
179 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
180 buf.m.planes = planes;
181 buf.length = 1;
182 }
183 int rc = ioctl(fd, VIDIOC_DQBUF, &buf);
184 if (rc < 0) {
185 CAMERA_LOGE("ioctl VIDIOC_DQBUF failed: %s\n", strerror(errno));
186 return RC_ERROR;
187 }
188
189 if (memoryType_ == V4L2_MEMORY_MMAP || memoryType_ == V4L2_MEMORY_DMABUF) {
190 if (adapterBufferMap_[buf.index].userBufPtr && adapterBufferMap_[buf.index].start) {
191 (void)memcpy_s(adapterBufferMap_[buf.index].userBufPtr, adapterBufferMap_[buf.index].length,
192 adapterBufferMap_[buf.index].start, adapterBufferMap_[buf.index].length);
193 }
194 }
195 std::lock_guard<std::mutex> l(bufferLock_);
196 auto IterMap = queueBuffers_.find(fd);
197 if (IterMap == queueBuffers_.end()) {
198 CAMERA_LOGE("std::map queueBuffers_ no fd\n");
199 return RC_ERROR;
200 }
201 auto& bufferMap = IterMap->second;
202 auto Iter = bufferMap.find(buf.index);
203 if (Iter == bufferMap.end()) {
204 CAMERA_LOGE("V4L2DequeueBuffer buf.index == %{public}d is not find in FrameMap\n", buf.index);
205 return RC_ERROR;
206 }
207 if (dequeueBuffer_ == nullptr) {
208 CAMERA_LOGE("V4L2DequeueBuffer buf.index == %{public}d no callback\n", buf.index);
209 bufferMap.erase(Iter);
210 return RC_ERROR;
211 }
212 dequeueBuffer_(Iter->second);
213 bufferMap.erase(Iter);
214 return RC_OK;
215 }
216
V4L2AllocBuffer(int fd,const std::shared_ptr<FrameSpec> & frameSpec)217 RetCode HosV4L2Buffers::V4L2AllocBuffer(int fd, const std::shared_ptr<FrameSpec>& frameSpec)
218 {
219 struct v4l2_buffer buf = {};
220 struct v4l2_plane planes[1] = {};
221 CAMERA_LOGD("V4L2AllocBuffer\n");
222
223 if (frameSpec == nullptr) {
224 CAMERA_LOGE("V4L2AllocBuffer frameSpec is NULL\n");
225 return RC_ERROR;
226 }
227
228 buf.type = bufferType_;
229 buf.memory = memoryType_;
230 buf.index = (uint32_t)frameSpec->buffer_->GetIndex();
231 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
232 buf.m.planes = planes;
233 buf.length = 1;
234 }
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 buf.index = %{public}d\n",
242 buf.length, frameSpec->buffer_->GetSize(), buf.index);
243 if (buf.length > frameSpec->buffer_->GetSize()) {
244 CAMERA_LOGE("RROR:user buff < V4L2 buf.length\n");
245 return RC_ERROR;
246 }
247 if (memoryType_ == V4L2_MEMORY_MMAP || memoryType_ == V4L2_MEMORY_DMABUF) {
248 return SetAdapterBuffer(fd, buf, frameSpec);
249 }
250 return RC_OK;
251 }
252
SetAdapterBuffer(int fd,struct v4l2_buffer & buf,const std::shared_ptr<FrameSpec> & frameSpec)253 RetCode HosV4L2Buffers::SetAdapterBuffer(int fd, struct v4l2_buffer &buf, const std::shared_ptr<FrameSpec>& frameSpec)
254 {
255 CAMERA_LOGD("HosV4L2Buffers::SetAdapterBuffer in.");
256 int32_t ret = 0;
257 int32_t index = (uint32_t)frameSpec->buffer_->GetIndex();
258
259 auto findIf = adapterBufferMap_.find(index);
260 if (findIf == adapterBufferMap_.end()) {
261 AdapterBuffer adapterBuffer = {nullptr, 0, 0, nullptr, 0, 0};
262 adapterBufferMap_.insert(std::make_pair(index, adapterBuffer));
263 }
264
265 adapterBufferMap_[index].userBufPtr = frameSpec->buffer_->GetVirAddress();
266
267 switch (memoryType_) {
268 case V4L2_MEMORY_MMAP:
269 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
270 adapterBufferMap_[index].length = buf.m.planes[0].length;
271 adapterBufferMap_[index].offset = buf.m.planes[0].m.mem_offset;
272 } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
273 adapterBufferMap_[index].length = buf.length;
274 adapterBufferMap_[index].offset = buf.m.offset;
275 }
276 if (adapterBufferMap_[buf.index].start == nullptr) {
277 adapterBufferMap_[buf.index].start = mmap(NULL, adapterBufferMap_[buf.index].length,
278 PROT_READ | PROT_WRITE, MAP_SHARED, fd, adapterBufferMap_[buf.index].offset);
279 if (adapterBufferMap_[buf.index].start == MAP_FAILED) {
280 CAMERA_LOGE("SetAdapterBuffer mmap failed.");
281 return RC_ERROR;
282 }
283 }
284 break;
285 case V4L2_MEMORY_DMABUF:
286 CAMERA_LOGD("HosV4L2Buffers::SetAdapterBuffer V4L2_MEMORY_DMABUF.");
287 if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
288 adapterBufferMap_[index].length = buf.m.planes[0].length;
289 } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
290 adapterBufferMap_[index].length = buf.length;
291 }
292 ret = SetDmabufOn(buf, frameSpec);
293 if (ret < 0) {
294 CAMERA_LOGE("SetDmabufOn err.\n");
295 return RC_ERROR;
296 }
297 break;
298 default:
299 CAMERA_LOGE("Incorrect memoryType\n");
300 return RC_ERROR;
301 }
302 CAMERA_LOGD("HosV4L2Buffers::SetAdapterBuffer out.");
303 return RC_OK;
304 }
305
SetDmabufOn(struct v4l2_buffer & buf,const std::shared_ptr<FrameSpec> & frameSpec)306 RetCode HosV4L2Buffers::SetDmabufOn(struct v4l2_buffer &buf, const std::shared_ptr<FrameSpec>& frameSpec)
307 {
308 CAMERA_LOGD("HosV4L2Buffers::SetDmabufOn in.");
309 int32_t ret = 0;
310 int32_t index = (uint32_t)frameSpec->buffer_->GetIndex();
311
312 int heapfd = open(DMA_BUF_FILE_NAME.c_str(), O_RDONLY | O_CLOEXEC);
313 if (heapfd < 0) {
314 CAMERA_LOGE("heapfd open err.\n");
315 return RC_ERROR;
316 }
317 struct dma_heap_allocation_data data = {
318 .len = buf.m.planes[0].length,
319 .fd_flags = O_RDWR | O_CLOEXEC,
320 };
321 ret = ioctl(heapfd, DMA_HEAP_IOCTL_ALLOC, &data);
322 if (ret < 0) {
323 close(heapfd);
324 CAMERA_LOGE("DMA_HEAP_IOCTL_ALLOC err.\n");
325 return RC_ERROR;
326 }
327 adapterBufferMap_[index].heapfd = heapfd;
328 adapterBufferMap_[index].dmafd = data.fd;
329 adapterBufferMap_[index].start = mmap(NULL, adapterBufferMap_[index].length, PROT_READ | PROT_WRITE,
330 MAP_SHARED, adapterBufferMap_[index].dmafd, 0);
331 if (adapterBufferMap_[index].start == MAP_FAILED) {
332 close(adapterBufferMap_[index].heapfd);
333 CAMERA_LOGE("SetDmabufOn dmabuf mmap err.\n");
334 return RC_ERROR;
335 }
336 struct dma_buf_sync sync = {0};
337 sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW;
338 ret = ioctl(adapterBufferMap_[buf.index].dmafd, DMA_BUF_IOCTL_SYNC, &sync);
339 if (ret < 0) {
340 if (munmap(adapterBufferMap_[index].start, adapterBufferMap_[index].length) < 0) {
341 CAMERA_LOGE("SetDmabufOn munmap err.\n");
342 }
343 close(adapterBufferMap_[index].dmafd);
344 close(adapterBufferMap_[index].heapfd);
345 CAMERA_LOGE("DMA_BUF_IOCTL_SYNC err.\n");
346 return RC_ERROR;
347 }
348 return RC_OK;
349 }
350
V4L2ReleaseBuffers(int fd)351 RetCode HosV4L2Buffers::V4L2ReleaseBuffers(int fd)
352 {
353 CAMERA_LOGE("HosV4L2Buffers::V4L2ReleaseBuffers\n");
354
355 std::lock_guard<std::mutex> l(bufferLock_);
356 queueBuffers_.erase(fd);
357
358 for (auto &mem : adapterBufferMap_) {
359 if (mem.second.dmafd > 0) {
360 struct dma_buf_sync sync = {0};
361 sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW;
362 int ret = ioctl(mem.second.dmafd, DMA_BUF_IOCTL_SYNC, &sync);
363 if (ret < 0) {
364 return RC_ERROR;
365 }
366 }
367 if (mem.second.start) {
368 if (munmap(mem.second.start, mem.second.length) < 0) {
369 return RC_ERROR;
370 }
371 }
372 if (mem.second.dmafd > 0) {
373 close(mem.second.dmafd);
374 }
375 if (mem.second.heapfd > 0) {
376 close(mem.second.heapfd);
377 }
378 }
379 adapterBufferMap_.clear();
380 return V4L2ReqBuffers(fd, 0);
381 }
382
SetCallback(BufCallback cb)383 void HosV4L2Buffers::SetCallback(BufCallback cb)
384 {
385 CAMERA_LOGD("HosV4L2Buffers::SetCallback OK.");
386 dequeueBuffer_ = cb;
387 }
388
Flush(int fd)389 RetCode HosV4L2Buffers::Flush(int fd)
390 {
391 CAMERA_LOGD("HosV4L2Buffers::Flush\n");
392 return RC_OK;
393 }
394 } // namespace OHOS::Camera
395