• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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