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