blob: 43195f66fe2820e8ee5120420ff67d67f7d9c072 [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
37
38static int mdrmFd = -1;
39
40static void destroy_gem_buffer(int drmFd, GemBuffer *gemBuf)
41{
42 int rc;
43 struct drm_gem_close gclose;
44
45 for (int i= 0; i < gemBuf->planeCount; ++i)
46 {
47 if (gemBuf->fd[i] >= 0)
48 {
49 close(gemBuf->fd[i]);
50 gemBuf->fd[i]= -1;
51 }
52 if (gemBuf->handle[i] > 0)
53 {
54 memset(&gclose, 0, sizeof(gclose));
55 gclose.handle= gemBuf->handle[i];
56 rc= ioctl(drmFd, DRM_IOCTL_GEM_CLOSE, &gclose);
57 if (rc < 0)
58 {
59 GST_ERROR("Failed to release gem buffer handle %d: DRM_IOCTL_MODE_DESTROY_DUMB rc %d errno %d",
60 gemBuf->handle[i], rc, errno );
61 }
62 gemBuf->handle[i]= 0;
63 }
64 }
65}
66
67void rotation_buffer_teardown(ROTBuffer *ROTbuf, int numBuffer)
68{
69 if (NULL == ROTbuf || 0 == numBuffer)
70 {
71 return;
72 }
73
74 for (int i= 0; i < numBuffer; ++i)
75 {
76 destroy_gem_buffer(mdrmFd, &ROTbuf[i].gemBuf);
77 }
78 free(ROTbuf);
79 ROTbuf = NULL;
80
81 if (mdrmFd >= 0)
82 {
83 close(mdrmFd);
84 mdrmFd= -1;
85 }
86
87}
88
89#define DEFAULT_DRM_NAME "/dev/dri/renderD128"
90static bool creat_gem_buffer(int drmFd, GemBuffer *gemBuf)
91{
92 bool result= false;
93 int rc;
94 struct drm_meson_gem_create gc;
95
96 for (int i= 0; i < gemBuf->planeCount; ++i)
97 {
98 gemBuf->fd[i]= -1;
99 memset(&gc, 0, sizeof(gc));
100 // NV12M
101 {
102 gc.flags= MESON_USE_VIDEO_PLANE;
103 if (i == 0)
104 {
105 gc.size= gemBuf->width*gemBuf->height;
106 }
107 else
108 {
109 gc.size= gemBuf->width*gemBuf->height/2;
110 }
111 gemBuf->stride[i]= gemBuf->width;
112 }
113 gemBuf->size[i]= gc.size;
114
115 rc= ioctl(drmFd, DRM_IOCTL_MESON_GEM_CREATE, &gc);
116 if (rc < 0)
117 {
118 GST_ERROR("Failed to create gem buffer: plane %d DRM_IOCTL_MESON_GEM_CREATE rc %d", i, rc);
119 goto exit;
120 }
121
122 gemBuf->handle[i]= gc.handle;
123 gemBuf->offset[i]= 0;
124
125 rc= drmPrimeHandleToFD(drmFd, gemBuf->handle[i], DRM_CLOEXEC | DRM_RDWR, &gemBuf->fd[i]);
126 if (rc < 0)
127 {
128 GST_ERROR("Failed to get fd for gem buf plane %d: handle %d drmPrimeHandleToFD rc %d",
129 i, gemBuf->handle[i], rc );
130 goto exit;
131 }
132
133 GST_DEBUG("create gem buf plane %d size (%dx%d) %u bytes stride %d offset %d handle %d fd %d",
134 i, gemBuf->width, gemBuf->height, gemBuf->size[i],
135 gemBuf->stride[i], gemBuf->offset[i], gemBuf->handle[i], gemBuf->fd[i] );
136 }
137
138 result= true;
139
140exit:
141
142 return result;
143}
144
145
146
147ROTBuffer* rotation_buffer_setup(int numPlanes, int width, int height, int numBuffer)
148{
149 bool result= false;
150 if (0 == numBuffer)
151 {
152 return NULL;
153 }
154 ROTBuffer* ROTbuf = (ROTBuffer*)calloc(numBuffer, sizeof(ROTBuffer));
155 if (!ROTbuf)
156 {
157 GST_ERROR("no memory for GemBuffer" );
158 return NULL;
159 }
160
161 char *drmName = DEFAULT_DRM_NAME;
162 mdrmFd= open(drmName, O_RDWR|O_CLOEXEC);
163 if (mdrmFd < 0)
164 {
165 GST_ERROR("Failed to open drm render node: %d", errno);
166 goto exit;
167 }
168
169 for (int i= 0; i < numBuffer; ++i)
170 {
171 ROTbuf[i].used = FALSE;
172 ROTbuf[i].gemBuf.planeCount= numPlanes;
173 ROTbuf[i].gemBuf.width= width;
174 ROTbuf[i].gemBuf.height= height;
175 for (int j= 0; j < MAX_PLANES; ++j)
176 {
177 ROTbuf[i].gemBuf.fd[j]= -1;
178 }
179 if (!creat_gem_buffer(mdrmFd, &ROTbuf[i].gemBuf))
180 {
181 GST_ERROR("Failed to allocate gem buffer");
182 goto exit;
183 }
184 }
185
186 result= true;
187
188exit:
189 if (!result)
190 {
191 rotation_buffer_teardown(ROTbuf, numBuffer);
192 ROTbuf = NULL;
193 }
194 return ROTbuf;
195}
196
197gboolean rotation_init(aml_ge2d_t* pAmlge2d, aml_ge2d_info_t **pge2dinfo)
198{
199 int ret = 0;
200 if (NULL == pAmlge2d)
201 {
202 return FALSE;
203 }
204
205 *pge2dinfo = &(pAmlge2d->ge2dinfo);
206 memset(pAmlge2d, 0, sizeof(aml_ge2d_t));
207
208 /* ge2d init */
209 ret = aml_ge2d_init(pAmlge2d);
210 if (ret < 0)
211 {
212 GST_ERROR("ge2d init failed");
213 return FALSE;
214 }
215 return TRUE;
216}
217
218gboolean rotation_exit(aml_ge2d_t* pAmlge2d)
219{
220 if (NULL == pAmlge2d)
221 {
222 return FALSE;
223 }
224
225 //ge2d release exit
226 aml_ge2d_exit(pAmlge2d);
227 return TRUE;
228}
229
230#if DUMP_ROTATION_DATA
231static int aml_write_file(int shared_fd, const char* file_name, int write_bytes)
232{
233 int fd = -1;
234 int write_num = 0;
235 char *vaddr = NULL;
236
237 if (shared_fd < 0 || !file_name || !write_bytes) {
238 printf("wrong params, read failed");
239 return -1;
240 }
241
242 vaddr = (char*)mmap(NULL, write_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, shared_fd, 0);
243 if (!vaddr) {
244 printf("%s,%d,mmap failed,Not enough memory\n",__func__, __LINE__);
245 return -1;
246 }
247
248 fd = open(file_name, O_RDWR | O_CREAT | O_APPEND, 0660);
249 if (fd < 0) {
250 printf("write file:%s open error\n", file_name);
251 return -1;
252 }
253
254 write_num = write(fd, vaddr, write_bytes);
255 if (write_num <= 0) {
256 printf("write file write_num=%d error\n", write_num);
257 }
258
259 close(fd);
260 munmap(vaddr, write_bytes);
261
262 return 0;
263}
264#endif
265
266gboolean get_rotation_size(int src_w, int src_h, int* dst_w, int* dst_h)
267{
268 if (NULL == dst_w || NULL == dst_h)
269 {
270 return FALSE;
271 }
272
273 int dst_width = src_w;
274 int dst_height = src_h;
275 // reduce to 720p
276 if (dst_width > 1280 || dst_height > 720)
277 {
278 int ratio = dst_width * 100 / dst_height;
279 if (ratio > 100)
280 {
281 dst_width = 1280;
282 dst_height = dst_width *100 / ratio;
283 }
284 else
285 {
286 dst_height = 720;
287 dst_width = dst_height * ratio / 100;
288 }
289 GST_DEBUG("ratio:%d, w:%d, h:%d\n", ratio, dst_width, dst_height);
290 }
291 *dst_w = dst_width/32*32;
292 *dst_h = dst_height;
293 return TRUE;
294}
295
296GstFlowReturn rotation_transform(aml_ge2d_info_t *pge2dinfo, GstBuffer *inbuf, ROTBuffer *ROTbuf, ROTATION_DEGREE ROTDegree)
297{
298 GstFlowReturn ret = GST_FLOW_ERROR;
299 GstMemory *mem;
300 int i;
301 int plane = 2;
302
303 GstVideoMeta *meta_data = NULL;
304
305 if (NULL == pge2dinfo || NULL == inbuf || NULL == ROTbuf)
306 {
307 return GST_FLOW_ERROR;
308 }
309
310 plane = gst_buffer_n_memory(inbuf);
311 for (i = 0; i < plane; i++)
312 {
313 mem = gst_buffer_peek_memory(inbuf, i);
314 g_return_val_if_fail(gst_is_drm_memory(mem), ret);
315 pge2dinfo->src_info[0].shared_fd[i] = gst_fd_memory_get_fd(mem);
316 pge2dinfo->dst_info.shared_fd[i] = ROTbuf->gemBuf.fd[i];
317 }
318
319 meta_data = gst_buffer_get_video_meta(inbuf);
320 // pge2dinfo->mem_sec = plugin->secure ? 1 : 0;
321 int src_width = meta_data->width;
322 int src_height = meta_data->height;
kaiqiang.xiange5044f22024-12-20 11:43:33 +0800323 int canvas_w = meta_data->stride[0];
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800324
325 int dst_width = ROTbuf->gemBuf.width;
326 int dst_height = ROTbuf->gemBuf.height;
327
328 // Align to 32-bit
329 dst_width = dst_width/32*32;
330
331 pge2dinfo->src_info[0].memtype = GE2D_CANVAS_ALLOC;
332 pge2dinfo->src_info[0].mem_alloc_type = AML_GE2D_MEM_DMABUF;
333 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 +0800334 pge2dinfo->src_info[0].canvas_w = canvas_w; /* input width */
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800335 pge2dinfo->src_info[0].canvas_h = src_height; /* input height */
336 pge2dinfo->src_info[0].format = PIXEL_FORMAT_YCbCr_420_SP_NV12;
337 pge2dinfo->src_info[0].rect.x = 0; /* input process area x */
338 pge2dinfo->src_info[0].rect.y = 0; /* input process area y */
339 pge2dinfo->src_info[0].rect.w = src_width; /* input process area w */
340 pge2dinfo->src_info[0].rect.h = src_height; /* input process area h */
341 pge2dinfo->src_info[0].plane_alpha = 0xFF; /* global plane alpha*/
342
343 pge2dinfo->dst_info.memtype = GE2D_CANVAS_ALLOC;
344 pge2dinfo->dst_info.mem_alloc_type = AML_GE2D_MEM_DMABUF;
345 pge2dinfo->dst_info.plane_number = plane; /* When allocating memory, it is a continuous block or separate multiple blocks */
346 pge2dinfo->dst_info.canvas_w = dst_width; /* output width */
347 pge2dinfo->dst_info.canvas_h = dst_height; /* output height */
348 pge2dinfo->dst_info.format = PIXEL_FORMAT_YCbCr_420_SP_NV12;
349 pge2dinfo->dst_info.rect.x = 0; /* output process area x */
350 pge2dinfo->dst_info.rect.y = 0; /* output process area y */
351 pge2dinfo->dst_info.rect.w = dst_width; /* output process area w */
352 pge2dinfo->dst_info.rect.h = dst_height; /* output process area h */
353 pge2dinfo->dst_info.plane_alpha = 0xFF; /* global plane alpha*/
354
355 pge2dinfo->dst_info.rotation = ROTDegree;
356 pge2dinfo->ge2d_op = AML_GE2D_STRETCHBLIT;
357
358 if (pge2dinfo->src_info[0].format == -1 || pge2dinfo->dst_info.format == -1) {
359 GST_ERROR("ge2d not support format src_info[0].format %d, dst_info.format %d",pge2dinfo->src_info[0].format, pge2dinfo->dst_info.format);
360 goto beach;
361 }
362
363#if DUMP_ROTATION_DATA
364 // DEBUG: dump src data
365 aml_write_file(pge2dinfo->src_info[0].shared_fd[0], "/tmp/input.yuv", src_width*src_height);
366 aml_write_file(pge2dinfo->src_info[0].shared_fd[1], "/tmp/input.yuv", src_width*src_height/2);
367#endif
368
369 GST_DEBUG("pge2dinfo: in_rect_w %d in_rect_h %d canvas_w %d canvas_h %d" , \
370 pge2dinfo->src_info[0].rect.w, pge2dinfo->src_info[0].rect.h, \
371 pge2dinfo->src_info[0].canvas_w,pge2dinfo->src_info[0].canvas_h);
372 ret = aml_ge2d_process(pge2dinfo);
373 if (ret < 0) {
374 GST_ERROR("ge2d process failed");
375 goto beach;
376 }
377 GST_DEBUG("pge2dinfo: out_rect_w %d out_rect_h %d canvas_w %d canvas_h %d" , \
378 pge2dinfo->dst_info.rect.w, pge2dinfo->dst_info.rect.h,\
379 pge2dinfo->dst_info.canvas_w,pge2dinfo->dst_info.canvas_h);
380#if DUMP_ROTATION_DATA
381 // DEBUG: dump dst data
382 aml_write_file(pge2dinfo->dst_info.shared_fd[0], "/tmp/output.yuv", dst_width*dst_height);
383 aml_write_file(pge2dinfo->dst_info.shared_fd[1], "/tmp/output.yuv", dst_width*dst_height/2);
384#endif
385 ret = GST_FLOW_OK;
386beach:
387 return ret;
388}