1 /*
2 * Copyright 2017 Rockchip Electronics Co., Ltd
3 * Author: Randy Li <randy.li@rock-chips.com>
4 *
5 * Copyright 2021 Rockchip Electronics Co., Ltd
6 * Author: Jeffy Chen <jeffy.chen@rock-chips.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <string.h>
29
30 #include <gst/allocators/gstdmabuf.h>
31
32 #include "gstmpp.h"
33 #include "gstmpph264enc.h"
34 #include "gstmpph265enc.h"
35 #include "gstmppvp8enc.h"
36 #include "gstmppjpegenc.h"
37 #include "gstmppjpegdec.h"
38 #include "gstmppvideodec.h"
39 #include "gstmppvpxalphadecodebin.h"
40
41 GST_DEBUG_CATEGORY_STATIC (mpp_debug);
42 #define GST_CAT_DEFAULT mpp_debug
43
44 struct gst_mpp_format
45 {
46 GstVideoFormat gst_format;
47 MppFrameFormat mpp_format;
48 #ifdef HAVE_RGA
49 RgaSURF_FORMAT rga_format;
50 #endif
51 gint pixel_stride0;
52 gboolean is_yuv;
53 };
54
55 #ifdef HAVE_RGA
56 #define GST_MPP_FORMAT(gst, mpp, rga, pixel_stride0, yuv) \
57 { GST_VIDEO_FORMAT_ ## gst, MPP_FMT_ ## mpp, RK_FORMAT_ ## rga, \
58 pixel_stride0, yuv }
59 #else
60 #define GST_MPP_FORMAT(gst, mpp, rga, pixel_stride0, yuv) \
61 { GST_VIDEO_FORMAT_ ## gst, MPP_FMT_ ## mpp, pixel_stride0, yuv}
62 #endif
63
64 struct gst_mpp_format gst_mpp_formats[] = {
65 GST_MPP_FORMAT (I420, YUV420P, YCbCr_420_P, 1, 1),
66 GST_MPP_FORMAT (YV12, BUTT, YCrCb_420_P, 1, 1),
67 GST_MPP_FORMAT (NV12, YUV420SP, YCbCr_420_SP, 1, 1),
68 GST_MPP_FORMAT (NV21, YUV420SP_VU, YCrCb_420_SP, 1, 1),
69 #ifdef HAVE_NV12_10LE40
70 GST_MPP_FORMAT (NV12_10LE40, YUV420SP_10BIT, YCbCr_420_SP_10B, 1, 1),
71 #else
72 GST_MPP_FORMAT (UNKNOWN, YUV420SP_10BIT, YCbCr_420_SP_10B, 1, 1),
73 #endif
74 #ifdef HAVE_NV16_10LE40
75 GST_MPP_FORMAT (NV16_10LE40, YUV422SP_10BIT, YCbCr_422_SP_10B, 1, 1),
76 #else
77 GST_MPP_FORMAT (UNKNOWN, YUV422SP_10BIT, YCbCr_422_SP_10B, 1, 1),
78 #endif
79 GST_MPP_FORMAT (Y42B, YUV422P, YCbCr_422_P, 1, 1),
80 GST_MPP_FORMAT (NV16, YUV422SP, YCbCr_422_SP, 1, 1),
81 GST_MPP_FORMAT (NV61, YUV422SP_VU, YCrCb_422_SP, 1, 1),
82 GST_MPP_FORMAT (NV24, YUV444SP, UNKNOWN, 1, 1),
83 GST_MPP_FORMAT (Y444, YUV444P, UNKNOWN, 1, 1),
84 GST_MPP_FORMAT (YUY2, YUV422_YUYV, UNKNOWN, 2, 1),
85 GST_MPP_FORMAT (YVYU, YUV422_YVYU, UNKNOWN, 2, 1),
86 GST_MPP_FORMAT (UYVY, YUV422_UYVY, UNKNOWN, 2, 1),
87 GST_MPP_FORMAT (VYUY, YUV422_VYUY, UNKNOWN, 2, 1),
88 GST_MPP_FORMAT (RGB16, RGB565LE, UNKNOWN, 2, 0),
89 GST_MPP_FORMAT (BGR16, BGR565LE, RGB_565, 2, 0),
90 GST_MPP_FORMAT (RGB, RGB888, RGB_888, 3, 0),
91 GST_MPP_FORMAT (BGR, BGR888, BGR_888, 3, 0),
92 GST_MPP_FORMAT (ARGB, ARGB8888, UNKNOWN, 4, 0),
93 GST_MPP_FORMAT (ABGR, ABGR8888, UNKNOWN, 4, 0),
94 GST_MPP_FORMAT (RGBA, RGBA8888, RGBA_8888, 4, 0),
95 GST_MPP_FORMAT (BGRA, BGRA8888, BGRA_8888, 4, 0),
96 GST_MPP_FORMAT (xRGB, ARGB8888, UNKNOWN, 4, 0),
97 GST_MPP_FORMAT (xBGR, ABGR8888, UNKNOWN, 4, 0),
98 GST_MPP_FORMAT (RGBx, RGBA8888, RGBX_8888, 4, 0),
99 GST_MPP_FORMAT (BGRx, BGRA8888, BGRX_8888, 4, 0),
100 };
101
102 #define GST_MPP_GET_FORMAT(type, format) ({ \
103 struct gst_mpp_format *_tmp; \
104 for (guint i = 0; i < ARRAY_SIZE (gst_mpp_formats) || (_tmp = NULL); i++) { \
105 _tmp = &gst_mpp_formats[i]; \
106 if (_tmp->type ## _format == (format)) break;\
107 }; _tmp; \
108 })
109
110 gboolean
gst_mpp_use_rga()111 gst_mpp_use_rga ()
112 {
113 static int mpp_use_rga = -1;
114
115 #ifdef HAVE_RGA
116 if (mpp_use_rga < 0) {
117 const gchar *buf = g_getenv ("GST_MPP_NO_RGA");
118 if (!buf || buf[0] == '0')
119 mpp_use_rga = 1;
120 else
121 mpp_use_rga = 0;
122 }
123 #endif
124
125 return mpp_use_rga > 0;
126 }
127
128 const gchar *
gst_mpp_video_format_to_string(GstVideoFormat format)129 gst_mpp_video_format_to_string (GstVideoFormat format)
130 {
131 if (format == GST_VIDEO_FORMAT_UNKNOWN)
132 return "UNKNOWN";
133
134 return gst_video_format_to_string (format);
135 }
136
137 GstVideoFormat
gst_mpp_mpp_format_to_gst_format(MppFrameFormat mpp_format)138 gst_mpp_mpp_format_to_gst_format (MppFrameFormat mpp_format)
139 {
140 struct gst_mpp_format *format = GST_MPP_GET_FORMAT (mpp,
141 mpp_format & MPP_FRAME_FMT_MASK);
142 return format ? format->gst_format : GST_VIDEO_FORMAT_UNKNOWN;
143 }
144
145 MppFrameFormat
gst_mpp_gst_format_to_mpp_format(GstVideoFormat gst_format)146 gst_mpp_gst_format_to_mpp_format (GstVideoFormat gst_format)
147 {
148 struct gst_mpp_format *format = GST_MPP_GET_FORMAT (gst, gst_format);
149 return format ? format->mpp_format : MPP_FMT_BUTT;
150 }
151
152 #ifdef HAVE_RGA
153 static RgaSURF_FORMAT
gst_mpp_mpp_format_to_rga_format(MppFrameFormat mpp_format)154 gst_mpp_mpp_format_to_rga_format (MppFrameFormat mpp_format)
155 {
156 struct gst_mpp_format *format = GST_MPP_GET_FORMAT (mpp,
157 mpp_format & MPP_FRAME_FMT_MASK);
158 return format ? format->rga_format : RK_FORMAT_UNKNOWN;
159 }
160
161 static RgaSURF_FORMAT
gst_mpp_gst_format_to_rga_format(GstVideoFormat gst_format)162 gst_mpp_gst_format_to_rga_format (GstVideoFormat gst_format)
163 {
164 struct gst_mpp_format *format = GST_MPP_GET_FORMAT (gst, gst_format);
165 return format ? format->rga_format : RK_FORMAT_UNKNOWN;
166 }
167
168 static gboolean
gst_mpp_set_rga_info(rga_info_t * info,RgaSURF_FORMAT rga_format,guint width,guint height,guint hstride,guint vstride)169 gst_mpp_set_rga_info (rga_info_t * info, RgaSURF_FORMAT rga_format,
170 guint width, guint height, guint hstride, guint vstride)
171 {
172 struct gst_mpp_format *format = GST_MPP_GET_FORMAT (rga, rga_format);
173
174 g_assert (format);
175 if (format->is_yuv) {
176 /* RGA requires yuv image rect align to 2 */
177 width &= ~1;
178 height &= ~1;
179
180 if (vstride % 2)
181 return FALSE;
182 }
183
184 if (info->fd < 0 && !info->virAddr)
185 return FALSE;
186
187 info->mmuFlag = 1;
188 rga_set_rect (&info->rect, 0, 0, width, height, hstride, vstride, rga_format);
189 return TRUE;
190 }
191
192 static gboolean
gst_mpp_rga_info_from_mpp_frame(rga_info_t * info,MppFrame mframe)193 gst_mpp_rga_info_from_mpp_frame (rga_info_t * info, MppFrame mframe)
194 {
195 MppFrameFormat mpp_format = mpp_frame_get_fmt (mframe);
196 MppBuffer mbuf = mpp_frame_get_buffer (mframe);
197 guint width = mpp_frame_get_width (mframe);
198 guint height = mpp_frame_get_height (mframe);
199 guint hstride = mpp_frame_get_hor_stride (mframe);
200 guint vstride = mpp_frame_get_ver_stride (mframe);
201 RgaSURF_FORMAT rga_format = gst_mpp_mpp_format_to_rga_format (mpp_format);
202
203 g_return_val_if_fail (mbuf, FALSE);
204
205 info->fd = mpp_buffer_get_fd (mbuf);
206
207 return gst_mpp_set_rga_info (info, rga_format, width, height,
208 hstride, vstride);
209 }
210
211 static gboolean
gst_mpp_rga_info_from_video_info(rga_info_t * info,GstVideoInfo * vinfo)212 gst_mpp_rga_info_from_video_info (rga_info_t * info, GstVideoInfo * vinfo)
213 {
214 GstVideoFormat format = GST_VIDEO_INFO_FORMAT (vinfo);
215 guint width = GST_VIDEO_INFO_WIDTH (vinfo);
216 guint height = GST_VIDEO_INFO_HEIGHT (vinfo);
217 guint hstride = GST_MPP_VIDEO_INFO_HSTRIDE (vinfo);
218 guint vstride = GST_MPP_VIDEO_INFO_VSTRIDE (vinfo);
219 RgaSURF_FORMAT rga_format = gst_mpp_gst_format_to_rga_format (format);
220
221 return gst_mpp_set_rga_info (info, rga_format, width, height,
222 hstride, vstride);
223 }
224
225 static gboolean
gst_mpp_rga_do_convert(rga_info_t * src_info,rga_info_t * dst_info)226 gst_mpp_rga_do_convert (rga_info_t * src_info, rga_info_t * dst_info)
227 {
228 static gint rga_supported = 1;
229 static gint rga_inited = 0;
230
231 if (!rga_supported || !gst_mpp_use_rga ())
232 return FALSE;
233
234 if (!rga_inited) {
235 if (c_RkRgaInit () < 0) {
236 rga_supported = 0;
237 GST_WARNING ("failed to init RGA");
238 return FALSE;
239 }
240 rga_inited = 1;
241 }
242
243 if (c_RkRgaBlit (src_info, dst_info, NULL) < 0) {
244 GST_WARNING ("failed to blit");
245 return FALSE;
246 }
247
248 GST_DEBUG ("converted with RGA");
249 return TRUE;
250 }
251
252 static gint
gst_mpp_rga_get_rotation(gint rotation)253 gst_mpp_rga_get_rotation (gint rotation)
254 {
255 switch (rotation) {
256 case 0:
257 return 0;
258 case 90:
259 return HAL_TRANSFORM_ROT_90;
260 case 180:
261 return HAL_TRANSFORM_ROT_180;
262 case 270:
263 return HAL_TRANSFORM_ROT_270;
264 default:
265 return -1;
266 }
267 }
268
269 gboolean
gst_mpp_rga_convert(GstBuffer * inbuf,GstVideoInfo * src_vinfo,GstMemory * out_mem,GstVideoInfo * dst_vinfo,gint rotation)270 gst_mpp_rga_convert (GstBuffer * inbuf, GstVideoInfo * src_vinfo,
271 GstMemory * out_mem, GstVideoInfo * dst_vinfo, gint rotation)
272 {
273 GstMapInfo mapinfo = { 0, };
274 gboolean ret;
275
276 rga_info_t src_info = { 0, };
277 rga_info_t dst_info = { 0, };
278
279 if (!gst_mpp_rga_info_from_video_info (&src_info, src_vinfo))
280 return FALSE;
281
282 if (!gst_mpp_rga_info_from_video_info (&dst_info, dst_vinfo))
283 return FALSE;
284
285 /* Prefer using dma fd */
286 if (gst_buffer_n_memory (inbuf) == 1) {
287 GstMemory *mem = gst_buffer_peek_memory (inbuf, 0);
288 gsize offset;
289
290 if (gst_is_dmabuf_memory (mem)) {
291 gst_memory_get_sizes (mem, &offset, NULL);
292 if (!offset)
293 src_info.fd = gst_dmabuf_memory_get_fd (mem);
294 }
295 }
296
297 if (src_info.fd <= 0) {
298 gst_buffer_map (inbuf, &mapinfo, GST_MAP_READ);
299 src_info.virAddr = mapinfo.data;
300 }
301
302 dst_info.fd = gst_dmabuf_memory_get_fd (out_mem);
303
304 src_info.rotation = gst_mpp_rga_get_rotation (rotation);
305 if (src_info.rotation < 0)
306 return FALSE;
307
308 ret = gst_mpp_rga_do_convert (&src_info, &dst_info);
309
310 gst_buffer_unmap (inbuf, &mapinfo);
311 return ret;
312 }
313
314 gboolean
gst_mpp_rga_convert_from_mpp_frame(MppFrame * mframe,GstMemory * out_mem,GstVideoInfo * dst_vinfo,gint rotation)315 gst_mpp_rga_convert_from_mpp_frame (MppFrame * mframe,
316 GstMemory * out_mem, GstVideoInfo * dst_vinfo, gint rotation)
317 {
318 rga_info_t src_info = { 0, };
319 rga_info_t dst_info = { 0, };
320
321 if (!gst_mpp_rga_info_from_mpp_frame (&src_info, mframe))
322 return FALSE;
323
324 if (!gst_mpp_rga_info_from_video_info (&dst_info, dst_vinfo))
325 return FALSE;
326
327 dst_info.fd = gst_dmabuf_memory_get_fd (out_mem);
328
329 src_info.rotation = gst_mpp_rga_get_rotation (rotation);
330 if (src_info.rotation < 0)
331 return FALSE;
332
333 return gst_mpp_rga_do_convert (&src_info, &dst_info);
334 }
335 #endif
336
337 void
gst_mpp_video_info_update_format(GstVideoInfo * info,GstVideoFormat format,guint width,guint height)338 gst_mpp_video_info_update_format (GstVideoInfo * info, GstVideoFormat format,
339 guint width, guint height)
340 {
341 GstCaps *caps;
342 const gchar *fmt = gst_mpp_video_format_to_string (format);
343
344 GST_DEBUG ("update format to %s (%dx%d)", fmt, width, height);
345
346 if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_UNKNOWN) {
347 gst_video_info_set_format (info, format, width, height);
348 return;
349 }
350
351 caps = gst_video_info_to_caps (info);
352 gst_caps_set_simple (caps, "format", G_TYPE_STRING, fmt,
353 "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
354 gst_video_info_from_caps (info, caps);
355 gst_caps_unref (caps);
356 }
357
358 gboolean
gst_mpp_video_info_align(GstVideoInfo * info,gint hstride,gint vstride)359 gst_mpp_video_info_align (GstVideoInfo * info, gint hstride, gint vstride)
360 {
361 GstVideoAlignment align;
362 guint stride;
363 guint i;
364
365 if (!hstride)
366 hstride = GST_MPP_ALIGN (GST_MPP_VIDEO_INFO_HSTRIDE (info));
367
368 if (!vstride)
369 vstride = GST_MPP_ALIGN (GST_MPP_VIDEO_INFO_VSTRIDE (info));
370
371 GST_DEBUG ("aligning %dx%d to %dx%d", GST_VIDEO_INFO_WIDTH (info),
372 GST_VIDEO_INFO_HEIGHT (info), hstride, vstride);
373
374 gst_video_alignment_reset (&align);
375
376 /* Apply vstride */
377 align.padding_bottom = vstride - GST_VIDEO_INFO_HEIGHT (info);
378 if (!gst_video_info_align (info, &align))
379 return FALSE;
380
381 /* Apply vstride for single-plane */
382 if (GST_VIDEO_INFO_N_PLANES (info) == 1)
383 GST_VIDEO_INFO_SIZE (info) =
384 GST_VIDEO_INFO_PLANE_STRIDE (info, 0) * vstride;
385
386 if (GST_VIDEO_INFO_PLANE_STRIDE (info, 0) == hstride)
387 return TRUE;
388
389 /* Apply hstride */
390 stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
391 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
392 GST_VIDEO_INFO_PLANE_STRIDE (info, i) =
393 GST_VIDEO_INFO_PLANE_STRIDE (info, i) * hstride / stride;
394 GST_VIDEO_INFO_PLANE_OFFSET (info, i) =
395 GST_VIDEO_INFO_PLANE_OFFSET (info, i) / stride * hstride;
396
397 GST_DEBUG ("plane %d, stride %d, offset %" G_GSIZE_FORMAT, i,
398 GST_VIDEO_INFO_PLANE_STRIDE (info, i),
399 GST_VIDEO_INFO_PLANE_OFFSET (info, i));
400 }
401 GST_VIDEO_INFO_SIZE (info) = GST_VIDEO_INFO_SIZE (info) / stride * hstride;
402
403 GST_DEBUG ("aligned size %" G_GSIZE_FORMAT, GST_VIDEO_INFO_SIZE (info));
404
405 return TRUE;
406 }
407
408 guint
gst_mpp_get_pixel_stride(GstVideoInfo * info)409 gst_mpp_get_pixel_stride (GstVideoInfo * info)
410 {
411 GstVideoFormat gst_format = GST_VIDEO_INFO_FORMAT (info);
412 struct gst_mpp_format *format = GST_MPP_GET_FORMAT (gst, gst_format);
413 guint hstride = GST_MPP_VIDEO_INFO_HSTRIDE (info);
414
415 if (!format)
416 return hstride;
417
418 return hstride / format->pixel_stride0;
419 }
420
421 static gboolean
plugin_init(GstPlugin * plugin)422 plugin_init (GstPlugin * plugin)
423 {
424 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "mpp", 0, "MPP");
425
426 gst_mpp_h264_enc_register (plugin, GST_RANK_PRIMARY + 1);
427 gst_mpp_h265_enc_register (plugin, GST_RANK_PRIMARY + 1);
428 gst_mpp_vp8_enc_register (plugin, GST_RANK_PRIMARY + 1);
429 gst_mpp_jpeg_enc_register (plugin, GST_RANK_PRIMARY + 1);
430
431 gst_mpp_video_dec_register (plugin, GST_RANK_PRIMARY + 1);
432 gst_mpp_jpeg_dec_register (plugin, GST_RANK_PRIMARY + 1);
433
434 #ifdef USE_VPXALPHADEC
435 gst_mpp_vpx_alpha_decode_bin_register (plugin,
436 GST_RANK_PRIMARY + GST_MPP_ALPHA_DECODE_BIN_RANK_OFFSET);
437 #endif
438
439 return TRUE;
440 }
441
442 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
443 GST_VERSION_MINOR,
444 rockchipmpp,
445 "Rockchip Mpp Video Plugin",
446 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
447