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