• 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 <unistd.h>
17 #include "aml_ge2d.h"
18 #include "v4l2_buffer.h"
19 namespace OHOS::Camera {
20 #define OUTPUT_V4L2_PIX_FMT V4L2_PIX_FMT_NV21
21 using Ge2dCanvasInfo = struct _Ge2dCanvasInfo {
22     uint32_t width;
23     uint32_t height;
24     uint32_t format;
25     int dmaFd;
26 };
pixelFormatV4l2ToGe2d(uint32_t v4l2PixelFmt)27 static uint32_t pixelFormatV4l2ToGe2d(uint32_t v4l2PixelFmt)
28 {
29     uint32_t ge2dPixelFmt;
30 
31     switch (v4l2PixelFmt) {
32         case V4L2_PIX_FMT_RGBA32:
33             ge2dPixelFmt = GE2D_PIXEL_FORMAT_RGBA_8888;
34             break;
35         case V4L2_PIX_FMT_RGBX32:
36             ge2dPixelFmt = GE2D_PIXEL_FORMAT_RGBX_8888;
37             break;
38         case V4L2_PIX_FMT_RGB24:
39             ge2dPixelFmt = GE2D_PIXEL_FORMAT_RGB_888;
40             break;
41         case V4L2_PIX_FMT_BGRA32:
42             ge2dPixelFmt = GE2D_PIXEL_FORMAT_BGRA_8888;
43             break;
44         case V4L2_PIX_FMT_YVU420:
45             ge2dPixelFmt = GE2D_PIXEL_FORMAT_YV12;
46             break;
47         case V4L2_PIX_FMT_GREY:
48             ge2dPixelFmt = GE2D_PIXEL_FORMAT_Y8;
49             break;
50         case V4L2_PIX_FMT_NV16:
51             ge2dPixelFmt = GE2D_PIXEL_FORMAT_YCbCr_422_SP;
52             break;
53         case V4L2_PIX_FMT_NV21:
54             ge2dPixelFmt = GE2D_PIXEL_FORMAT_YCrCb_420_SP;
55             break;
56         case V4L2_PIX_FMT_UYVY:
57             ge2dPixelFmt = GE2D_PIXEL_FORMAT_YCbCr_422_UYVY;
58             break;
59         case V4L2_PIX_FMT_BGR24:
60             ge2dPixelFmt = GE2D_PIXEL_FORMAT_BGR_888;
61             break;
62         case V4L2_PIX_FMT_NV12:
63             ge2dPixelFmt = GE2D_PIXEL_FORMAT_YCbCr_420_SP_NV12;
64             break;
65         default:
66             ge2dPixelFmt = GE2D_PIXEL_FORMAT_INVALID;
67             break;
68     }
69 
70     return ge2dPixelFmt;
71 }
72 
doBlit(aml_ge2d_t * ge2d,Ge2dCanvasInfo & srcInfo,Ge2dCanvasInfo & dstInfo)73 static int doBlit(aml_ge2d_t *ge2d, Ge2dCanvasInfo & srcInfo, Ge2dCanvasInfo & dstInfo)
74 {
75     int ret;
76     aml_ge2d_info_t *pge2dinfo = &ge2d->ge2dinfo;
77     uint32_t srcCanvasW, srcCanvasH;
78     uint32_t srcFmt;
79     int srcDmaFd;
80     uint32_t dstCanvasW, dstCanvasH;
81     uint32_t dstFmt;
82     int dstDmaFd;
83 
84     srcCanvasW = srcInfo.width;
85     srcCanvasH = srcInfo.height;
86     srcFmt = srcInfo.format;
87     srcDmaFd = srcInfo.dmaFd;
88 
89     dstCanvasW = dstInfo.width;
90     dstCanvasH = dstInfo.height;
91     dstFmt = dstInfo.format;
92     dstDmaFd = dstInfo.dmaFd;
93 
94     if (!ge2d || !srcCanvasW || !srcCanvasH || !dstCanvasW || !dstCanvasH || srcDmaFd<0 || dstDmaFd<0) {
95         CAMERA_LOGE("Invalid param.");
96         return -1;
97     }
98 
99     pge2dinfo->offset = 0;
100     pge2dinfo->ge2d_op = GE2D_OP_STRETCHBLIT;
101     pge2dinfo->blend_mode = GE2D_BLEND_MODE_NONE;
102 
103     pge2dinfo->src_info[0].plane_number = 1;
104     pge2dinfo->src_info[0].layer_mode = GE2D_LAYER_MODE_INVALID;
105     pge2dinfo->src_info[0].plane_alpha = 0xff;
106     pge2dinfo->src_info[0].memtype = GE2D_CANVAS_ALLOC;
107     pge2dinfo->src_info[1].memtype = GE2D_CANVAS_TYPE_INVALID;
108     pge2dinfo->src_info[0].mem_alloc_type = GE2D_MEM_DMABUF;
109     pge2dinfo->src_info[1].mem_alloc_type = GE2D_MEM_DMABUF;
110     pge2dinfo->src_info[0].shared_fd[0] = srcDmaFd;
111     pge2dinfo->src_info[0].canvas_w = srcCanvasW;
112     pge2dinfo->src_info[0].canvas_h = srcCanvasH;
113     pge2dinfo->src_info[0].format = srcFmt;
114     pge2dinfo->src_info[0].rect.x = 0;
115     pge2dinfo->src_info[0].rect.y = 0;
116     pge2dinfo->src_info[0].rect.w = srcCanvasW;
117     pge2dinfo->src_info[0].rect.h = srcCanvasH;
118 
119     pge2dinfo->dst_info.plane_number = 1;
120     pge2dinfo->dst_info.rotation = GE2D_ROTATION_0;
121     pge2dinfo->dst_info.mem_alloc_type = GE2D_MEM_DMABUF;
122     pge2dinfo->dst_info.memtype = GE2D_CANVAS_ALLOC;
123     pge2dinfo->dst_info.shared_fd[0] = dstDmaFd;
124     pge2dinfo->dst_info.canvas_w = dstCanvasW;
125     pge2dinfo->dst_info.canvas_h = dstCanvasH;
126     pge2dinfo->dst_info.format = dstFmt;
127     pge2dinfo->dst_info.rect.x = 0;
128     pge2dinfo->dst_info.rect.y = 0;
129     pge2dinfo->dst_info.rect.w = dstCanvasW;
130     pge2dinfo->dst_info.rect.h = dstCanvasH;
131 
132     ret = aml_ge2d_process(pge2dinfo);
133     if (ret) {
134         CAMERA_LOGE("aml_ge2d_process() failed. ret=%{public}d", ret);
135     }
136 
137     return ret;
138 }
139 
getTickMs()140 static inline uint64_t getTickMs()
141 {
142     struct timespec ts = {};
143     clock_gettime(CLOCK_MONOTONIC, &ts);
144     return ts.tv_nsec / 1000000ULL + ts.tv_sec * 1000ULL;
145 }
146 
HosV4L2Buffers(enum v4l2_memory memType,enum v4l2_buf_type bufferType)147 HosV4L2Buffers::HosV4L2Buffers(enum v4l2_memory memType, enum v4l2_buf_type bufferType)
148     : memoryType_(memType), bufferType_(bufferType)
149 {
150     CAMERA_LOGD("HosV4L2Buffers::HosV4L2Buffers enter");
151 
152     int ret;
153     ge2d_ = calloc(sizeof(aml_ge2d_t), 1);
154     if (!ge2d_) {
155         CAMERA_LOGE("No enough memory for ge2d ctx");
156         return;
157     }
158 
159     if (aml_ge2d_init((aml_ge2d_t*)ge2d_)) {
160         free(ge2d_);
161         ge2d_ = NULL;
162         CAMERA_LOGE("aml_ge2d_init() failed.");
163         return;
164     }
165 
166     CAMERA_LOGD("HosV4L2Buffers::HosV4L2Buffers exit");
167 }
168 
~HosV4L2Buffers()169 HosV4L2Buffers::~HosV4L2Buffers()
170 {
171     if (ge2d_) {
172         aml_ge2d_exit((aml_ge2d_t*)ge2d_);
173         CAMERA_LOGD("aml_ge2d_exit()");
174         free(ge2d_);
175     }
176 }
177 
V4L2ReqBuffers(int fd,int unsigned buffCont)178 RetCode HosV4L2Buffers::V4L2ReqBuffers(int fd, int unsigned buffCont)
179 {
180     struct v4l2_requestbuffers req = {};
181 
182     CAMERA_LOGD("V4L2ReqBuffers buffCont %d\n", buffCont);
183 
184     req.count = buffCont;
185     req.type = bufferType_;
186     req.memory = memoryType_;
187 
188     if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
189         CAMERA_LOGE("does not support memory mapping %s\n", strerror(errno));
190         return RC_ERROR;
191     }
192 
193     if (req.count != buffCont) {
194         CAMERA_LOGE("error Insufficient buffer memory on \n");
195 
196         req.count = 0;
197         req.type = bufferType_;
198         req.memory = memoryType_;
199         if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
200             CAMERA_LOGE("V4L2ReqBuffers does not release buffer	%s\n", strerror(errno));
201             return RC_ERROR;
202         }
203 
204         return RC_ERROR;
205     }
206 
207     return RC_OK;
208 }
209 
V4L2QueueBuffer(int fd,const std::shared_ptr<FrameSpec> & frameSpec)210 RetCode HosV4L2Buffers::V4L2QueueBuffer(int fd, const std::shared_ptr<FrameSpec>& frameSpec)
211 {
212     struct v4l2_buffer buf = {};
213     struct v4l2_plane planes[1] = {};
214 
215     if (frameSpec == nullptr) {
216         CAMERA_LOGE("V4L2QueueBuffer: frameSpec is NULL\n");
217         return RC_ERROR;
218     }
219 
220     buf.index = (uint32_t)frameSpec->buffer_->GetIndex();
221     buf.type = bufferType_;
222     buf.memory = memoryType_;
223 
224     if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
225         buf.m.planes = planes;
226         buf.m.planes[0].length = frameSpec->buffer_->GetSize();
227         buf.m.planes[0].m.userptr = (unsigned long)frameSpec->buffer_->GetVirAddress();
228         buf.length = 1;
229 
230         CAMERA_LOGD("++++++++++++ V4L2QueueBuffer buf.index = %{public}d, buf.length = \
231             %{public}d, buf.m.userptr = %{public}p\n", \
232             buf.index, buf.m.planes[0].length, (void*)buf.m.planes[0].m.userptr);
233     } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
234         buf.length = frameSpec->buffer_->GetSize();
235         buf.m.userptr = (unsigned long)frameSpec->buffer_->GetVirAddress();
236 
237         CAMERA_LOGD("++++++++++++ V4L2QueueBuffer buf.index = %{public}d, buf.length = \
238             %{public}d, buf.m.userptr = %{public}p\n", \
239             buf.index, buf.length, (void*)buf.m.userptr);
240     }
241 
242     std::lock_guard<std::mutex> l(bufferLock_);
243     int rc = ioctl(fd, VIDIOC_QBUF, &buf);
244     if (rc < 0) {
245         CAMERA_LOGE("ioctl VIDIOC_QBUF failed: %s\n", strerror(errno));
246         return RC_ERROR;
247     }
248 
249     auto itr = queueBuffers_.find(fd);
250     if (itr != queueBuffers_.end()) {
251         itr->second[buf.index] = frameSpec;
252         CAMERA_LOGD("insert frameMap fd = %{public}d buf.index = %{public}d\n", fd, buf.index);
253     } else {
254         FrameMap frameMap;
255         frameMap.insert(std::make_pair(buf.index, frameSpec));
256         queueBuffers_.insert(std::make_pair(fd, frameMap));
257         CAMERA_LOGD("insert fd = %{public}d buf.index = %{public}d\n", fd, buf.index);
258     }
259 
260     return RC_OK;
261 }
262 
V4L2DequeueBuffer(int fd)263 RetCode HosV4L2Buffers::V4L2DequeueBuffer(int fd)
264 {
265     struct v4l2_buffer buf = {};
266     struct v4l2_plane planes[1] = {};
267 
268     buf.type = bufferType_;
269     buf.memory = memoryType_;
270 
271     if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
272         buf.m.planes = planes;
273         buf.length = 1;
274     }
275     int rc = ioctl(fd, VIDIOC_DQBUF, &buf);
276     if (rc < 0) {
277         CAMERA_LOGE("ioctl VIDIOC_DQBUF failed: %s\n", strerror(errno));
278         return RC_ERROR;
279     }
280 
281     if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
282         CAMERA_LOGD("---------------- V4L2DequeueBuffer index = %{public}d buf.m.ptr = %{public}p len = %{public}d\n",
283             buf.index, (void*)buf.m.planes[0].m.userptr, buf.m.planes[0].length);
284     } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
285         CAMERA_LOGD("---------------- V4L2DequeueBuffer index = %{public}d buf.m.ptr = %{public}p len = %{public}d\n",
286             buf.index, (void*)buf.m.userptr, buf.length);
287     }
288 
289     std::lock_guard<std::mutex> l(bufferLock_);
290 
291     auto IterMap = queueBuffers_.find(fd);
292     if (IterMap == queueBuffers_.end()) {
293         CAMERA_LOGE("std::map queueBuffers_ no fd\n");
294         return RC_ERROR;
295     }
296     auto& bufferMap = IterMap->second;
297 
298     auto Iter = bufferMap.find(buf.index);
299     if (Iter == bufferMap.end()) {
300         CAMERA_LOGE("V4L2DequeueBuffer buf.index == %{public}d is not find in FrameMap\n", buf.index);
301         return RC_ERROR;
302     }
303 
304     if (dequeueBuffer_ == nullptr) {
305         CAMERA_LOGE("V4L2DequeueBuffer buf.index == %{public}d no callback\n", buf.index);
306         bufferMap.erase(Iter);
307         return RC_ERROR;
308     }
309 
310     if (memoryType_ == V4L2_MEMORY_MMAP) {
311         BlitForMMAP(fd, buf.index, Iter->second->buffer_);
312     }
313 
314     // callback to up
315     dequeueBuffer_(Iter->second);
316 
317     bufferMap.erase(Iter);
318 
319     return RC_OK;
320 }
321 
V4L2AllocBuffer(int fd,const std::shared_ptr<FrameSpec> & frameSpec)322 RetCode HosV4L2Buffers::V4L2AllocBuffer(int fd, const std::shared_ptr<FrameSpec>& frameSpec)
323 {
324     struct v4l2_buffer buf = {};
325     struct v4l2_plane planes[1] = {};
326     CAMERA_LOGD("V4L2AllocBuffer\n");
327 
328     if (frameSpec == nullptr) {
329         CAMERA_LOGE("V4L2AllocBuffer frameSpec is NULL\n");
330         return RC_ERROR;
331     }
332 
333     switch (memoryType_) {
334         case V4L2_MEMORY_MMAP:
335             break;
336         case V4L2_MEMORY_USERPTR:
337             buf.type = bufferType_;
338             buf.memory = memoryType_;
339             buf.index = (uint32_t)frameSpec->buffer_->GetIndex();
340 
341             if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
342                 buf.m.planes = planes;
343                 buf.length = 1;
344             }
345             CAMERA_LOGD("V4L2_MEMORY_USERPTR Print the cnt: %{public}d\n", buf.index);
346 
347             if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
348                 CAMERA_LOGE("error: ioctl VIDIOC_QUERYBUF failed: %{public}s\n", strerror(errno));
349                 return RC_ERROR;
350             }
351 
352             CAMERA_LOGD("buf.length = %{public}d frameSpec->buffer_->GetSize() = %{public}d\n", buf.length,
353                         frameSpec->buffer_->GetSize());
354 
355             if (buf.length > frameSpec->buffer_->GetSize()) {
356                 CAMERA_LOGE("ERROR:user buff < V4L2 buf.length\n");
357                 return RC_ERROR;
358             }
359 
360             break;
361         case V4L2_MEMORY_OVERLAY:
362             // to do something
363             break;
364 
365         case V4L2_MEMORY_DMABUF:
366             // to do something
367             break;
368 
369         default:
370             CAMERA_LOGE("It can not be happening - incorrect memory type\n");
371             return RC_ERROR;
372     }
373 
374     return RC_OK;
375 }
376 
V4L2ReleaseBuffers(int fd)377 RetCode HosV4L2Buffers::V4L2ReleaseBuffers(int fd)
378 {
379     CAMERA_LOGE("HosV4L2Buffers::V4L2ReleaseBuffers\n");
380 
381     std::lock_guard<std::mutex> l(bufferLock_);
382     queueBuffers_.erase(fd);
383 
384     return V4L2ReqBuffers(fd, 0);
385 }
386 
SetCallback(BufCallback cb)387 void HosV4L2Buffers::SetCallback(BufCallback cb)
388 {
389     CAMERA_LOGD("HosV4L2Buffers::SetCallback OK.");
390     dequeueBuffer_ = cb;
391 }
392 
Flush(int fd)393 RetCode HosV4L2Buffers::Flush(int fd)
394 {
395     CAMERA_LOGD("HosV4L2Buffers::Flush enter\n");
396     std::lock_guard<std::mutex> l(bufferLock_);
397 
398     if (dequeueBuffer_ == nullptr) {
399         CAMERA_LOGE("HosV4L2Buffers::Flush  dequeueBuffer_ == nullptr");
400         return RC_ERROR;
401     }
402 
403     auto IterMap = queueBuffers_.find(fd);
404     if (IterMap == queueBuffers_.end()) {
405         CAMERA_LOGE("HosV4L2Buffers::Flush std::map queueBuffers_ no fd");
406         return RC_ERROR;
407     }
408     auto &bufferMap = IterMap->second;
409 
410     for (auto &it : bufferMap) {
411         std::shared_ptr<FrameSpec> frameSpec = it.second;
412         CAMERA_LOGD("HosV4L2Buffers::Flush throw up buffer begin, buffpool=%{public}d",
413                     (int32_t)frameSpec->bufferPoolId_);
414         frameSpec->buffer_->SetBufferStatus(CAMERA_BUFFER_STATUS_INVALID);
415         dequeueBuffer_(frameSpec);
416         CAMERA_LOGD("HosV4L2Buffers::Flush throw up buffer end");
417     }
418 
419     bufferMap.clear();
420 
421     CAMERA_LOGD("HosV4L2Buffers::Flush exit\n");
422 
423     return RC_OK;
424 }
425 
BlitForMMAP(int fd,uint32_t fromIndex,std::shared_ptr<IBuffer> toBuffer)426 RetCode HosV4L2Buffers::BlitForMMAP(int fd, uint32_t fromIndex, std::shared_ptr<IBuffer> toBuffer)
427 {
428     int ret;
429     struct v4l2_format fmt = {};
430     struct v4l2_exportbuffer expbuf = {};
431     int32_t dstDma = toBuffer->GetFileDescriptor();
432     uint32_t dstWidth = toBuffer->GetWidth();
433     uint32_t dstHeight = toBuffer->GetHeight();
434     int32_t srcDma = -1;
435     uint32_t srcWidth = 0;
436     uint32_t srcHeight = 0;
437     uint32_t srcFmt;
438     uint32_t dstFmt;
439     uint64_t tickBegin = getTickMs();
440     Ge2dCanvasInfo srcInfo;
441     Ge2dCanvasInfo dstInfo;
442 
443     // Get src format
444     fmt.type = bufferType_;
445     ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
446     if (ret < 0) {
447         CAMERA_LOGE("error: ioctl VIDIOC_G_FMT failed: %s\n", strerror(errno));
448         return RC_ERROR;
449     }
450 
451     if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
452         srcWidth = fmt.fmt.pix_mp.width;
453         srcHeight = fmt.fmt.pix_mp.height;
454         srcFmt = pixelFormatV4l2ToGe2d(fmt.fmt.pix_mp.pixelformat);
455     } else if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
456         srcWidth = fmt.fmt.pix.width;
457         srcHeight = fmt.fmt.pix.height;
458         srcFmt = pixelFormatV4l2ToGe2d(fmt.fmt.pix.pixelformat);
459     }
460 
461     dstFmt = pixelFormatV4l2ToGe2d(OUTPUT_V4L2_PIX_FMT);
462     if (!srcFmt || !dstFmt) {
463         CAMERA_LOGE("Error: Invalid srcFmt or dstFmt: %{public}d, %{public}d", srcFmt, dstFmt);
464         return RC_ERROR;
465     }
466 
467     // Export dma fd
468     expbuf.type = bufferType_;
469     expbuf.index = fromIndex;
470     ret = ioctl(fd, VIDIOC_EXPBUF, &expbuf);
471     if (ret < 0) {
472         CAMERA_LOGE("error: ioctl VIDIOC_EXPBUF failed: ret = %{public}d, %{public}s\n", ret, strerror(errno));
473         return RC_ERROR;
474     }
475     srcDma = expbuf.fd;
476 
477     // DO blit
478     srcInfo.width = srcWidth;
479     srcInfo.height = srcHeight;
480     srcInfo.format = srcFmt;
481     srcInfo.dmaFd = srcDma;
482     dstInfo.width = dstWidth;
483     dstInfo.height = dstHeight;
484     dstInfo.format = dstFmt;
485     dstInfo.dmaFd = dstDma;
486     ret = doBlit((aml_ge2d_t*)ge2d_, srcInfo, dstInfo);
487 
488     close(srcDma);
489 
490     CAMERA_LOGD("fromIndex=%{public}d, blit ret=%{public}d, use_time=%{public}llums", \
491                 fromIndex, ret, getTickMs()-tickBegin);
492 
493     CAMERA_LOGD("Format=%{public}d, Size=%{public}d, EncodeType=%{public}d", \
494                 toBuffer->GetFormat(), toBuffer->GetSize(), toBuffer->GetEncodeType());
495 
496     return ret ? RC_ERROR : RC_OK;
497 }
498 } // namespace OHOS::Camera
499