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