blob: c6e396489254031109a6c2858d0bef6d9c529cf5 [file] [log] [blame]
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001/* GStreamer
2 * Copyright (C) 2022 amlogic
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17 * Boston, MA 02110-1335, USA.
18 */
19
20#include <fcntl.h>
21#include <unistd.h>
22#include <string.h>
23#include <stdbool.h>
24#include <sys/utsname.h>
25#include "resourcemanage.h"
26#include "meson_drm.h"
27#include <errno.h>
28#include <sys/mman.h>
29#include <sys/ioctl.h>
30#include <stdio.h>
31#include <drm/drm_fourcc.h>
32#include "ge2drotation.h"
33//#include <gst/gstdrmbufferpool.h>
34#include <gst/allocators/gstdmabuf.h>
35
36#define DUMP_ROTATION_DATA 0
hanghang.luoa84a72e2024-12-18 13:37:58 +080037#define UVM_IOC_MAGIC 'U'
38#define UVM_IOC_SYNC_INFO _IOWR(UVM_IOC_MAGIC, 14, struct uvm_sync_info)
39#define DEFAULT_UVM_NAME "/dev/uvm"
40#define DEFAULT_DRM_NAME "/dev/dri/renderD128"
41static int uvmFd = -1;
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +080042static int mdrmFd = -1;
hanghang.luoa84a72e2024-12-18 13:37:58 +080043struct uvm_sync_info {
44 int src_fd;
45 int dst_fd;
46};
47
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +080048
49static void destroy_gem_buffer(int drmFd, GemBuffer *gemBuf)
50{
51 int rc;
52 struct drm_gem_close gclose;
53
54 for (int i= 0; i < gemBuf->planeCount; ++i)
55 {
56 if (gemBuf->fd[i] >= 0)
57 {
58 close(gemBuf->fd[i]);
59 gemBuf->fd[i]= -1;
60 }
61 if (gemBuf->handle[i] > 0)
62 {
63 memset(&gclose, 0, sizeof(gclose));
64 gclose.handle= gemBuf->handle[i];
65 rc= ioctl(drmFd, DRM_IOCTL_GEM_CLOSE, &gclose);
66 if (rc < 0)
67 {
68 GST_ERROR("Failed to release gem buffer handle %d: DRM_IOCTL_MODE_DESTROY_DUMB rc %d errno %d",
69 gemBuf->handle[i], rc, errno );
70 }
71 gemBuf->handle[i]= 0;
72 }
73 }
74}
75
76void rotation_buffer_teardown(ROTBuffer *ROTbuf, int numBuffer)
77{
78 if (NULL == ROTbuf || 0 == numBuffer)
79 {
80 return;
81 }
82
83 for (int i= 0; i < numBuffer; ++i)
84 {
85 destroy_gem_buffer(mdrmFd, &ROTbuf[i].gemBuf);
86 }
hanghang.luoa84a72e2024-12-18 13:37:58 +080087
88 if (ROTbuf->src_buf)
89 {
90 gst_buffer_unref(ROTbuf->src_buf);
91 ROTbuf->src_buf = NULL;
92 }
93
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +080094 free(ROTbuf);
95 ROTbuf = NULL;
96
97 if (mdrmFd >= 0)
98 {
99 close(mdrmFd);
100 mdrmFd= -1;
101 }
102
hanghang.luoa84a72e2024-12-18 13:37:58 +0800103 if (uvmFd >= 0)
104 {
105 close(uvmFd);
106 uvmFd= -1;
107 }
108
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800109}
110
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800111static bool creat_gem_buffer(int drmFd, GemBuffer *gemBuf)
112{
113 bool result= false;
114 int rc;
115 struct drm_meson_gem_create gc;
116
117 for (int i= 0; i < gemBuf->planeCount; ++i)
118 {
119 gemBuf->fd[i]= -1;
120 memset(&gc, 0, sizeof(gc));
121 // NV12M
122 {
123 gc.flags= MESON_USE_VIDEO_PLANE;
124 if (i == 0)
125 {
126 gc.size= gemBuf->width*gemBuf->height;
127 }
128 else
129 {
130 gc.size= gemBuf->width*gemBuf->height/2;
131 }
132 gemBuf->stride[i]= gemBuf->width;
133 }
134 gemBuf->size[i]= gc.size;
135
136 rc= ioctl(drmFd, DRM_IOCTL_MESON_GEM_CREATE, &gc);
137 if (rc < 0)
138 {
139 GST_ERROR("Failed to create gem buffer: plane %d DRM_IOCTL_MESON_GEM_CREATE rc %d", i, rc);
140 goto exit;
141 }
142
143 gemBuf->handle[i]= gc.handle;
144 gemBuf->offset[i]= 0;
145
146 rc= drmPrimeHandleToFD(drmFd, gemBuf->handle[i], DRM_CLOEXEC | DRM_RDWR, &gemBuf->fd[i]);
147 if (rc < 0)
148 {
149 GST_ERROR("Failed to get fd for gem buf plane %d: handle %d drmPrimeHandleToFD rc %d",
150 i, gemBuf->handle[i], rc );
151 goto exit;
152 }
153
154 GST_DEBUG("create gem buf plane %d size (%dx%d) %u bytes stride %d offset %d handle %d fd %d",
155 i, gemBuf->width, gemBuf->height, gemBuf->size[i],
156 gemBuf->stride[i], gemBuf->offset[i], gemBuf->handle[i], gemBuf->fd[i] );
157 }
158
159 result= true;
160
161exit:
162
163 return result;
164}
165
166
167
168ROTBuffer* rotation_buffer_setup(int numPlanes, int width, int height, int numBuffer)
169{
170 bool result= false;
171 if (0 == numBuffer)
172 {
173 return NULL;
174 }
175 ROTBuffer* ROTbuf = (ROTBuffer*)calloc(numBuffer, sizeof(ROTBuffer));
176 if (!ROTbuf)
177 {
178 GST_ERROR("no memory for GemBuffer" );
179 return NULL;
180 }
181
182 char *drmName = DEFAULT_DRM_NAME;
183 mdrmFd= open(drmName, O_RDWR|O_CLOEXEC);
184 if (mdrmFd < 0)
185 {
186 GST_ERROR("Failed to open drm render node: %d", errno);
187 goto exit;
188 }
189
hanghang.luoa84a72e2024-12-18 13:37:58 +0800190 uvmFd = open(DEFAULT_UVM_NAME, O_RDONLY | O_CLOEXEC);
191 if (uvmFd < 0)
192 {
193 GST_ERROR("Failed to open uvm node: %d", errno);
194 goto exit;
195 }
196
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800197 for (int i= 0; i < numBuffer; ++i)
198 {
199 ROTbuf[i].used = FALSE;
200 ROTbuf[i].gemBuf.planeCount= numPlanes;
201 ROTbuf[i].gemBuf.width= width;
202 ROTbuf[i].gemBuf.height= height;
hanghang.luoa84a72e2024-12-18 13:37:58 +0800203 ROTbuf[i].src_buf = NULL;
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800204 for (int j= 0; j < MAX_PLANES; ++j)
205 {
206 ROTbuf[i].gemBuf.fd[j]= -1;
207 }
208 if (!creat_gem_buffer(mdrmFd, &ROTbuf[i].gemBuf))
209 {
210 GST_ERROR("Failed to allocate gem buffer");
211 goto exit;
212 }
213 }
214
215 result= true;
216
217exit:
218 if (!result)
219 {
220 rotation_buffer_teardown(ROTbuf, numBuffer);
221 ROTbuf = NULL;
222 }
223 return ROTbuf;
224}
225
226gboolean rotation_init(aml_ge2d_t* pAmlge2d, aml_ge2d_info_t **pge2dinfo)
227{
228 int ret = 0;
229 if (NULL == pAmlge2d)
230 {
231 return FALSE;
232 }
233
234 *pge2dinfo = &(pAmlge2d->ge2dinfo);
235 memset(pAmlge2d, 0, sizeof(aml_ge2d_t));
236
237 /* ge2d init */
238 ret = aml_ge2d_init(pAmlge2d);
239 if (ret < 0)
240 {
241 GST_ERROR("ge2d init failed");
242 return FALSE;
243 }
244 return TRUE;
245}
246
247gboolean rotation_exit(aml_ge2d_t* pAmlge2d)
248{
249 if (NULL == pAmlge2d)
250 {
251 return FALSE;
252 }
253
254 //ge2d release exit
255 aml_ge2d_exit(pAmlge2d);
256 return TRUE;
257}
258
259#if DUMP_ROTATION_DATA
260static int aml_write_file(int shared_fd, const char* file_name, int write_bytes)
261{
262 int fd = -1;
263 int write_num = 0;
264 char *vaddr = NULL;
265
266 if (shared_fd < 0 || !file_name || !write_bytes) {
267 printf("wrong params, read failed");
268 return -1;
269 }
270
271 vaddr = (char*)mmap(NULL, write_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, shared_fd, 0);
272 if (!vaddr) {
273 printf("%s,%d,mmap failed,Not enough memory\n",__func__, __LINE__);
274 return -1;
275 }
276
277 fd = open(file_name, O_RDWR | O_CREAT | O_APPEND, 0660);
278 if (fd < 0) {
279 printf("write file:%s open error\n", file_name);
280 return -1;
281 }
282
283 write_num = write(fd, vaddr, write_bytes);
284 if (write_num <= 0) {
285 printf("write file write_num=%d error\n", write_num);
286 }
287
288 close(fd);
289 munmap(vaddr, write_bytes);
290
291 return 0;
292}
293#endif
294
295gboolean get_rotation_size(int src_w, int src_h, int* dst_w, int* dst_h)
296{
297 if (NULL == dst_w || NULL == dst_h)
298 {
299 return FALSE;
300 }
301
302 int dst_width = src_w;
303 int dst_height = src_h;
304 // reduce to 720p
305 if (dst_width > 1280 || dst_height > 720)
306 {
307 int ratio = dst_width * 100 / dst_height;
308 if (ratio > 100)
309 {
310 dst_width = 1280;
311 dst_height = dst_width *100 / ratio;
312 }
313 else
314 {
315 dst_height = 720;
316 dst_width = dst_height * ratio / 100;
317 }
318 GST_DEBUG("ratio:%d, w:%d, h:%d\n", ratio, dst_width, dst_height);
319 }
320 *dst_w = dst_width/32*32;
321 *dst_h = dst_height;
322 return TRUE;
323}
324
hanghang.luoa84a72e2024-12-18 13:37:58 +0800325static int uvm_bind_vframe(int fd, int src_fd, int dst_fd)
326{
327 int rc;
328 struct uvm_sync_info sync_info;
329 sync_info.src_fd = src_fd;
330 sync_info.dst_fd = dst_fd;
331 rc = ioctl (fd, UVM_IOC_SYNC_INFO, &sync_info);
332 return rc;
333}
334
335
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800336GstFlowReturn rotation_transform(aml_ge2d_info_t *pge2dinfo, GstBuffer *inbuf, ROTBuffer *ROTbuf, ROTATION_DEGREE ROTDegree)
337{
338 GstFlowReturn ret = GST_FLOW_ERROR;
339 GstMemory *mem;
340 int i;
341 int plane = 2;
342
343 GstVideoMeta *meta_data = NULL;
344
345 if (NULL == pge2dinfo || NULL == inbuf || NULL == ROTbuf)
346 {
347 return GST_FLOW_ERROR;
348 }
349
350 plane = gst_buffer_n_memory(inbuf);
351 for (i = 0; i < plane; i++)
352 {
353 mem = gst_buffer_peek_memory(inbuf, i);
354 g_return_val_if_fail(gst_is_drm_memory(mem), ret);
355 pge2dinfo->src_info[0].shared_fd[i] = gst_fd_memory_get_fd(mem);
356 pge2dinfo->dst_info.shared_fd[i] = ROTbuf->gemBuf.fd[i];
hanghang.luoa84a72e2024-12-18 13:37:58 +0800357
358 // bind vframe
359 int rc = uvm_bind_vframe(uvmFd, pge2dinfo->src_info[0].shared_fd[i], pge2dinfo->dst_info.shared_fd[i]);
360 if (rc) {
361 GST_ERROR ("bind vframe, UVM_IOC_SYNC_INFO error %d", rc);
362 }
363 ROTbuf->src_buf = inbuf;
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800364 }
365
366 meta_data = gst_buffer_get_video_meta(inbuf);
367 // pge2dinfo->mem_sec = plugin->secure ? 1 : 0;
368 int src_width = meta_data->width;
369 int src_height = meta_data->height;
kaiqiang.xiange5044f22024-12-20 11:43:33 +0800370 int canvas_w = meta_data->stride[0];
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800371
372 int dst_width = ROTbuf->gemBuf.width;
373 int dst_height = ROTbuf->gemBuf.height;
374
375 // Align to 32-bit
376 dst_width = dst_width/32*32;
377
378 pge2dinfo->src_info[0].memtype = GE2D_CANVAS_ALLOC;
379 pge2dinfo->src_info[0].mem_alloc_type = AML_GE2D_MEM_DMABUF;
380 pge2dinfo->src_info[0].plane_number = plane; /* When allocating memory, it is a continuous block or separate multiple blocks */
kaiqiang.xiange5044f22024-12-20 11:43:33 +0800381 pge2dinfo->src_info[0].canvas_w = canvas_w; /* input width */
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800382 pge2dinfo->src_info[0].canvas_h = src_height; /* input height */
383 pge2dinfo->src_info[0].format = PIXEL_FORMAT_YCbCr_420_SP_NV12;
384 pge2dinfo->src_info[0].rect.x = 0; /* input process area x */
385 pge2dinfo->src_info[0].rect.y = 0; /* input process area y */
386 pge2dinfo->src_info[0].rect.w = src_width; /* input process area w */
387 pge2dinfo->src_info[0].rect.h = src_height; /* input process area h */
388 pge2dinfo->src_info[0].plane_alpha = 0xFF; /* global plane alpha*/
389
390 pge2dinfo->dst_info.memtype = GE2D_CANVAS_ALLOC;
391 pge2dinfo->dst_info.mem_alloc_type = AML_GE2D_MEM_DMABUF;
392 pge2dinfo->dst_info.plane_number = plane; /* When allocating memory, it is a continuous block or separate multiple blocks */
393 pge2dinfo->dst_info.canvas_w = dst_width; /* output width */
394 pge2dinfo->dst_info.canvas_h = dst_height; /* output height */
395 pge2dinfo->dst_info.format = PIXEL_FORMAT_YCbCr_420_SP_NV12;
396 pge2dinfo->dst_info.rect.x = 0; /* output process area x */
397 pge2dinfo->dst_info.rect.y = 0; /* output process area y */
398 pge2dinfo->dst_info.rect.w = dst_width; /* output process area w */
399 pge2dinfo->dst_info.rect.h = dst_height; /* output process area h */
400 pge2dinfo->dst_info.plane_alpha = 0xFF; /* global plane alpha*/
401
402 pge2dinfo->dst_info.rotation = ROTDegree;
403 pge2dinfo->ge2d_op = AML_GE2D_STRETCHBLIT;
404
405 if (pge2dinfo->src_info[0].format == -1 || pge2dinfo->dst_info.format == -1) {
406 GST_ERROR("ge2d not support format src_info[0].format %d, dst_info.format %d",pge2dinfo->src_info[0].format, pge2dinfo->dst_info.format);
407 goto beach;
408 }
409
410#if DUMP_ROTATION_DATA
411 // DEBUG: dump src data
412 aml_write_file(pge2dinfo->src_info[0].shared_fd[0], "/tmp/input.yuv", src_width*src_height);
413 aml_write_file(pge2dinfo->src_info[0].shared_fd[1], "/tmp/input.yuv", src_width*src_height/2);
414#endif
415
416 GST_DEBUG("pge2dinfo: in_rect_w %d in_rect_h %d canvas_w %d canvas_h %d" , \
417 pge2dinfo->src_info[0].rect.w, pge2dinfo->src_info[0].rect.h, \
418 pge2dinfo->src_info[0].canvas_w,pge2dinfo->src_info[0].canvas_h);
419 ret = aml_ge2d_process(pge2dinfo);
420 if (ret < 0) {
421 GST_ERROR("ge2d process failed");
422 goto beach;
423 }
424 GST_DEBUG("pge2dinfo: out_rect_w %d out_rect_h %d canvas_w %d canvas_h %d" , \
425 pge2dinfo->dst_info.rect.w, pge2dinfo->dst_info.rect.h,\
426 pge2dinfo->dst_info.canvas_w,pge2dinfo->dst_info.canvas_h);
427#if DUMP_ROTATION_DATA
428 // DEBUG: dump dst data
429 aml_write_file(pge2dinfo->dst_info.shared_fd[0], "/tmp/output.yuv", dst_width*dst_height);
430 aml_write_file(pge2dinfo->dst_info.shared_fd[1], "/tmp/output.yuv", dst_width*dst_height/2);
431#endif
432 ret = GST_FLOW_OK;
433beach:
434 return ret;
435}