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
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <string.h>
30
31 #include "gstmppallocator.h"
32 #include "gstmppenc.h"
33
34 #define GST_CAT_DEFAULT mpp_enc_debug
35 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
36
37 #define parent_class gst_mpp_enc_parent_class
38 G_DEFINE_ABSTRACT_TYPE (GstMppEnc, gst_mpp_enc, GST_TYPE_VIDEO_ENCODER);
39
40 #define MPP_PENDING_MAX 2 /* Max number of MPP pending frame */
41
42 #define GST_MPP_ENC_TASK_STARTED(encoder) \
43 (gst_pad_get_task_state ((encoder)->srcpad) == GST_TASK_STARTED)
44
45 #define GST_MPP_ENC_MUTEX(encoder) (&GST_MPP_ENC (encoder)->mutex)
46
47 #define GST_MPP_ENC_LOCK(encoder) \
48 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder); \
49 g_mutex_lock (GST_MPP_ENC_MUTEX (encoder)); \
50 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
51
52 #define GST_MPP_ENC_UNLOCK(encoder) \
53 g_mutex_unlock (GST_MPP_ENC_MUTEX (encoder));
54
55 #define GST_MPP_ENC_EVENT_MUTEX(encoder) (&GST_MPP_ENC (encoder)->event_mutex)
56 #define GST_MPP_ENC_EVENT_COND(encoder) (&GST_MPP_ENC (encoder)->event_cond)
57
58 #define GST_MPP_ENC_BROADCAST(encoder) \
59 g_mutex_lock (GST_MPP_ENC_EVENT_MUTEX (encoder)); \
60 g_cond_broadcast (GST_MPP_ENC_EVENT_COND (encoder)); \
61 g_mutex_unlock (GST_MPP_ENC_EVENT_MUTEX (encoder));
62
63 #define GST_MPP_ENC_WAIT(encoder, condition) \
64 g_mutex_lock (GST_MPP_ENC_EVENT_MUTEX (encoder)); \
65 while (!(condition)) \
66 g_cond_wait (GST_MPP_ENC_EVENT_COND (encoder), \
67 GST_MPP_ENC_EVENT_MUTEX (encoder)); \
68 g_mutex_unlock (GST_MPP_ENC_EVENT_MUTEX (encoder));
69
70 #define DEFAULT_PROP_HEADER_MODE MPP_ENC_HEADER_MODE_DEFAULT /* First frame */
71 #define DEFAULT_PROP_SEI_MODE MPP_ENC_SEI_MODE_DISABLE
72 #define DEFAULT_PROP_RC_MODE MPP_ENC_RC_MODE_CBR
73 #define DEFAULT_PROP_ROTATION 0
74 #define DEFAULT_PROP_GOP -1 /* Same as FPS */
75 #define DEFAULT_PROP_MAX_REENC 1
76 #define DEFAULT_PROP_BPS 0 /* Auto */
77 #define DEFAULT_PROP_BPS_MIN 0 /* Auto */
78 #define DEFAULT_PROP_BPS_MAX 0 /* Auto */
79 #define DEFAULT_PROP_WIDTH 0 /* Original */
80 #define DEFAULT_PROP_HEIGHT 0 /* Original */
81 #define DEFAULT_PROP_ZERO_COPY_PKT TRUE
82
83 /* Input isn't ARM AFBC by default */
84 static GstVideoFormat DEFAULT_PROP_ARM_AFBC = FALSE;
85
86 #define DEFAULT_FPS 30
87
88 enum
89 {
90 PROP_0,
91 PROP_HEADER_MODE,
92 PROP_RC_MODE,
93 PROP_ROTATION,
94 PROP_SEI_MODE,
95 PROP_GOP,
96 PROP_MAX_REENC,
97 PROP_BPS,
98 PROP_BPS_MIN,
99 PROP_BPS_MAX,
100 PROP_WIDTH,
101 PROP_HEIGHT,
102 PROP_ZERO_COPY_PKT,
103 PROP_ARM_AFBC,
104 PROP_LAST,
105 };
106
107 static const MppFrameFormat gst_mpp_enc_formats[] = {
108 MPP_FMT_YUV420SP,
109 MPP_FMT_YUV420P,
110 MPP_FMT_YUV422_YUYV,
111 MPP_FMT_YUV422_UYVY,
112 MPP_FMT_YUV444SP,
113 MPP_FMT_YUV444P,
114 MPP_FMT_RGB565LE,
115 MPP_FMT_BGR565LE,
116 MPP_FMT_ARGB8888,
117 MPP_FMT_ABGR8888,
118 MPP_FMT_RGBA8888,
119 MPP_FMT_BGRA8888,
120 };
121
122 static gboolean
gst_mpp_enc_format_supported(MppFrameFormat format)123 gst_mpp_enc_format_supported (MppFrameFormat format)
124 {
125 guint i;
126
127 for (i = 0; i < ARRAY_SIZE (gst_mpp_enc_formats); i++) {
128 if (format == gst_mpp_enc_formats[i])
129 return TRUE;
130 }
131
132 return FALSE;
133 }
134
135 gboolean
gst_mpp_enc_supported(MppCodingType mpp_type)136 gst_mpp_enc_supported (MppCodingType mpp_type)
137 {
138 MppCtx mpp_ctx;
139 MppApi *mpi;
140
141 if (mpp_create (&mpp_ctx, &mpi))
142 return FALSE;
143
144 if (mpp_init (mpp_ctx, MPP_CTX_ENC, mpp_type)) {
145 mpp_destroy (mpp_ctx);
146 return FALSE;
147 }
148
149 mpp_destroy (mpp_ctx);
150 return TRUE;
151 }
152
153 static gboolean
gst_mpp_enc_video_info_matched(GstVideoInfo * info,GstVideoInfo * other)154 gst_mpp_enc_video_info_matched (GstVideoInfo * info, GstVideoInfo * other)
155 {
156 guint i;
157
158 if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_INFO_FORMAT (other))
159 return FALSE;
160
161 if (GST_VIDEO_INFO_SIZE (info) != GST_VIDEO_INFO_SIZE (other))
162 return FALSE;
163
164 if (GST_VIDEO_INFO_WIDTH (info) != GST_VIDEO_INFO_WIDTH (other))
165 return FALSE;
166
167 if (GST_VIDEO_INFO_HEIGHT (info) != GST_VIDEO_INFO_HEIGHT (other))
168 return FALSE;
169
170 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
171 if (GST_VIDEO_INFO_PLANE_STRIDE (info,
172 i) != GST_VIDEO_INFO_PLANE_STRIDE (other, i))
173 return FALSE;
174 if (GST_VIDEO_INFO_PLANE_OFFSET (info,
175 i) != GST_VIDEO_INFO_PLANE_OFFSET (other, i))
176 return FALSE;
177 }
178
179 return TRUE;
180 }
181
182 gboolean
gst_mpp_enc_video_info_align(GstVideoInfo * info)183 gst_mpp_enc_video_info_align (GstVideoInfo * info)
184 {
185 gint vstride = 0;
186
187 /* Allow skipping vstride aligning for RKVENC */
188 if (g_getenv ("GST_MPP_ENC_UNALIGNED_VSTRIDE"))
189 vstride = GST_MPP_VIDEO_INFO_VSTRIDE (info);
190
191 return gst_mpp_video_info_align (info, 0, vstride);
192 }
193
194 static void
gst_mpp_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)195 gst_mpp_enc_set_property (GObject * object,
196 guint prop_id, const GValue * value, GParamSpec * pspec)
197 {
198 GstVideoEncoder *encoder = GST_VIDEO_ENCODER (object);
199 GstMppEnc *self = GST_MPP_ENC (encoder);
200
201 switch (prop_id) {
202 case PROP_HEADER_MODE:{
203 MppEncHeaderMode header_mode = g_value_get_enum (value);
204 if (self->header_mode == header_mode)
205 return;
206
207 self->header_mode = header_mode;
208 break;
209 }
210 case PROP_SEI_MODE:{
211 MppEncSeiMode sei_mode = g_value_get_enum (value);
212 if (self->sei_mode == sei_mode)
213 return;
214
215 self->sei_mode = sei_mode;
216 break;
217 }
218 case PROP_RC_MODE:{
219 MppEncRcMode rc_mode = g_value_get_enum (value);
220 if (self->rc_mode == rc_mode)
221 return;
222
223 self->rc_mode = rc_mode;
224 break;
225 }
226 case PROP_GOP:{
227 gint gop = g_value_get_int (value);
228 if (self->gop == gop)
229 return;
230
231 self->gop = gop;
232 break;
233 }
234 case PROP_MAX_REENC:{
235 guint max_reenc = g_value_get_uint (value);
236 if (self->max_reenc == max_reenc)
237 return;
238
239 self->max_reenc = max_reenc;
240 break;
241 }
242 case PROP_BPS:{
243 guint bps = g_value_get_uint (value);
244 if (self->bps == bps)
245 return;
246
247 self->bps = bps;
248 break;
249 }
250 case PROP_BPS_MIN:{
251 guint bps_min = g_value_get_uint (value);
252 if (self->bps_min == bps_min)
253 return;
254
255 self->bps_min = bps_min;
256 break;
257 }
258 case PROP_BPS_MAX:{
259 guint bps_max = g_value_get_uint (value);
260 if (self->bps_max == bps_max)
261 return;
262
263 self->bps_max = bps_max;
264 break;
265 }
266 case PROP_ROTATION:{
267 if (self->input_state)
268 GST_WARNING_OBJECT (encoder, "unable to change rotation");
269 else
270 self->rotation = g_value_get_enum (value);
271 return;
272 }
273 case PROP_WIDTH:{
274 if (self->input_state)
275 GST_WARNING_OBJECT (encoder, "unable to change width");
276 else
277 self->width = g_value_get_uint (value);
278 return;
279 }
280 case PROP_HEIGHT:{
281 if (self->input_state)
282 GST_WARNING_OBJECT (encoder, "unable to change height");
283 else
284 self->height = g_value_get_uint (value);
285 return;
286 }
287 case PROP_ZERO_COPY_PKT:{
288 self->zero_copy_pkt = g_value_get_boolean (value);
289 return;
290 }
291 case PROP_ARM_AFBC:{
292 if (self->input_state)
293 GST_WARNING_OBJECT (encoder, "unable to change ARM AFBC");
294 else
295 self->arm_afbc = g_value_get_boolean (value);
296 return;
297 }
298 default:
299 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
300 return;
301 }
302
303 self->prop_dirty = TRUE;
304 }
305
306 static void
gst_mpp_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)307 gst_mpp_enc_get_property (GObject * object,
308 guint prop_id, GValue * value, GParamSpec * pspec)
309 {
310 GstVideoEncoder *encoder = GST_VIDEO_ENCODER (object);
311 GstMppEnc *self = GST_MPP_ENC (encoder);
312
313 switch (prop_id) {
314 case PROP_HEADER_MODE:
315 g_value_set_enum (value, self->header_mode);
316 break;
317 case PROP_SEI_MODE:
318 g_value_set_enum (value, self->sei_mode);
319 break;
320 case PROP_RC_MODE:
321 g_value_set_enum (value, self->rc_mode);
322 break;
323 case PROP_ROTATION:
324 g_value_set_enum (value, self->rotation);
325 break;
326 case PROP_GOP:
327 g_value_set_int (value, self->gop);
328 break;
329 case PROP_MAX_REENC:
330 g_value_set_uint (value, self->max_reenc);
331 break;
332 case PROP_BPS:
333 g_value_set_uint (value, self->bps);
334 break;
335 case PROP_BPS_MIN:
336 g_value_set_uint (value, self->bps_min);
337 break;
338 case PROP_BPS_MAX:
339 g_value_set_uint (value, self->bps_max);
340 break;
341 case PROP_WIDTH:
342 g_value_set_uint (value, self->width);
343 break;
344 case PROP_HEIGHT:
345 g_value_set_uint (value, self->height);
346 break;
347 case PROP_ZERO_COPY_PKT:
348 g_value_set_boolean (value, self->zero_copy_pkt);
349 break;
350 case PROP_ARM_AFBC:
351 g_value_set_boolean (value, self->arm_afbc);
352 break;
353 default:
354 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
355 return;
356 }
357 }
358
359 gboolean
gst_mpp_enc_apply_properties(GstVideoEncoder * encoder)360 gst_mpp_enc_apply_properties (GstVideoEncoder * encoder)
361 {
362 GstMppEnc *self = GST_MPP_ENC (encoder);
363 GstVideoInfo *info = &self->info;
364 gint fps_num = GST_VIDEO_INFO_FPS_N (info);
365 gint fps_denorm = GST_VIDEO_INFO_FPS_D (info);
366 gint fps = fps_num / fps_denorm;
367
368 if (!self->prop_dirty)
369 return TRUE;
370
371 self->prop_dirty = FALSE;
372
373 if (self->mpi->control (self->mpp_ctx, MPP_ENC_SET_SEI_CFG, &self->sei_mode))
374 GST_WARNING_OBJECT (self, "failed to set sei mode");
375
376 if (self->mpi->control (self->mpp_ctx, MPP_ENC_SET_HEADER_MODE,
377 &self->header_mode))
378 GST_WARNING_OBJECT (self, "failed to set header mode");
379
380 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:gop",
381 self->gop < 0 ? fps : self->gop);
382 mpp_enc_cfg_set_u32 (self->mpp_cfg, "rc:max_reenc_times", self->max_reenc);
383 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:mode", self->rc_mode);
384
385 if (!self->bps)
386 self->bps =
387 GST_VIDEO_INFO_WIDTH (info) * GST_VIDEO_INFO_HEIGHT (info) / 8 * fps;
388
389 if (!self->bps || self->rc_mode == MPP_ENC_RC_MODE_FIXQP) {
390 /* BPS settings are ignored */
391 } else if (self->rc_mode == MPP_ENC_RC_MODE_CBR) {
392 /* CBR mode has narrow bound */
393 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_target", self->bps);
394 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_max",
395 self->bps_max ? : self->bps * 17 / 16);
396 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_min",
397 self->bps_min ? : self->bps * 15 / 16);
398 } else if (self->rc_mode == MPP_ENC_RC_MODE_VBR) {
399 /* VBR mode has wide bound */
400 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_target", self->bps);
401 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_max",
402 self->bps_max ? : self->bps * 17 / 16);
403 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_min",
404 self->bps_min ? : self->bps * 1 / 16);
405 }
406
407 if (self->mpi->control (self->mpp_ctx, MPP_ENC_SET_CFG, self->mpp_cfg)) {
408 GST_WARNING_OBJECT (self, "failed to set enc cfg");
409 return FALSE;
410 }
411
412 return TRUE;
413 }
414
415 gboolean
gst_mpp_enc_set_src_caps(GstVideoEncoder * encoder,GstCaps * caps)416 gst_mpp_enc_set_src_caps (GstVideoEncoder * encoder, GstCaps * caps)
417 {
418 GstMppEnc *self = GST_MPP_ENC (encoder);
419 GstVideoInfo *info = &self->info;
420 GstVideoCodecState *output_state;
421
422 gst_caps_set_simple (caps,
423 "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH (info),
424 "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT (info), NULL);
425
426 GST_DEBUG_OBJECT (self, "output caps: %" GST_PTR_FORMAT, caps);
427
428 output_state = gst_video_encoder_set_output_state (encoder,
429 caps, self->input_state);
430
431 GST_VIDEO_INFO_WIDTH (&output_state->info) = GST_VIDEO_INFO_WIDTH (info);
432 GST_VIDEO_INFO_HEIGHT (&output_state->info) = GST_VIDEO_INFO_HEIGHT (info);
433 gst_video_codec_state_unref (output_state);
434
435 return gst_video_encoder_negotiate (encoder);
436 }
437
438 static void
gst_mpp_enc_stop_task(GstVideoEncoder * encoder,gboolean drain)439 gst_mpp_enc_stop_task (GstVideoEncoder * encoder, gboolean drain)
440 {
441 GstMppEnc *self = GST_MPP_ENC (encoder);
442 GstTask *task = encoder->srcpad->task;
443
444 if (!GST_MPP_ENC_TASK_STARTED (encoder))
445 return;
446
447 GST_DEBUG_OBJECT (self, "stopping encoding thread");
448
449 /* Discard pending frames */
450 if (!drain)
451 self->pending_frames = 0;
452
453 GST_MPP_ENC_BROADCAST (encoder);
454
455 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
456 /* Wait for task thread to pause */
457 if (task) {
458 GST_OBJECT_LOCK (task);
459 while (GST_TASK_STATE (task) == GST_TASK_STARTED)
460 GST_TASK_WAIT (task);
461 GST_OBJECT_UNLOCK (task);
462 }
463
464 gst_pad_stop_task (encoder->srcpad);
465 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
466 }
467
468 static void
gst_mpp_enc_reset(GstVideoEncoder * encoder,gboolean drain,gboolean final)469 gst_mpp_enc_reset (GstVideoEncoder * encoder, gboolean drain, gboolean final)
470 {
471 GstMppEnc *self = GST_MPP_ENC (encoder);
472
473 GST_MPP_ENC_LOCK (encoder);
474
475 GST_DEBUG_OBJECT (self, "resetting");
476
477 self->flushing = TRUE;
478 self->draining = drain;
479
480 gst_mpp_enc_stop_task (encoder, drain);
481
482 self->flushing = final;
483 self->draining = FALSE;
484
485 self->mpi->reset (self->mpp_ctx);
486 self->task_ret = GST_FLOW_OK;
487 self->pending_frames = 0;
488
489 /* Force re-apply prop */
490 self->prop_dirty = TRUE;
491
492 GST_MPP_ENC_UNLOCK (encoder);
493 }
494
495 static gboolean
gst_mpp_enc_start(GstVideoEncoder * encoder)496 gst_mpp_enc_start (GstVideoEncoder * encoder)
497 {
498 GstMppEnc *self = GST_MPP_ENC (encoder);
499
500 GST_DEBUG_OBJECT (self, "starting");
501
502 gst_video_info_init (&self->info);
503
504 self->allocator = gst_mpp_allocator_new ();
505 if (!self->allocator)
506 return FALSE;
507
508 gst_mpp_allocator_set_cacheable (self->allocator, FALSE);
509
510 if (mpp_create (&self->mpp_ctx, &self->mpi))
511 goto err_unref_alloc;
512
513 if (mpp_init (self->mpp_ctx, MPP_CTX_ENC, self->mpp_type))
514 goto err_destroy_mpp;
515
516 if (mpp_frame_init (&self->mpp_frame))
517 goto err_destroy_mpp;
518
519 if (mpp_enc_cfg_init (&self->mpp_cfg))
520 goto err_deinit_frame;
521
522 if (self->mpi->control (self->mpp_ctx, MPP_ENC_GET_CFG, self->mpp_cfg))
523 goto err_deinit_cfg;
524
525 self->task_ret = GST_FLOW_OK;
526 self->input_state = NULL;
527 self->flushing = FALSE;
528 self->pending_frames = 0;
529
530 g_mutex_init (&self->mutex);
531
532 g_mutex_init (&self->event_mutex);
533 g_cond_init (&self->event_cond);
534
535 GST_DEBUG_OBJECT (self, "started");
536
537 return TRUE;
538
539 err_deinit_cfg:
540 mpp_enc_cfg_deinit (self->mpp_cfg);
541 err_deinit_frame:
542 mpp_frame_deinit (&self->mpp_frame);
543 err_destroy_mpp:
544 mpp_destroy (self->mpp_ctx);
545 err_unref_alloc:
546 gst_object_unref (self->allocator);
547 return FALSE;
548 }
549
550 static gboolean
gst_mpp_enc_stop(GstVideoEncoder * encoder)551 gst_mpp_enc_stop (GstVideoEncoder * encoder)
552 {
553 GstMppEnc *self = GST_MPP_ENC (encoder);
554
555 GST_DEBUG_OBJECT (self, "stopping");
556
557 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
558 gst_mpp_enc_reset (encoder, FALSE, TRUE);
559 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
560
561 g_cond_clear (&self->event_cond);
562 g_mutex_clear (&self->event_mutex);
563
564 g_mutex_clear (&self->mutex);
565
566 mpp_enc_cfg_deinit (self->mpp_cfg);
567 mpp_frame_set_buffer (self->mpp_frame, NULL);
568 mpp_frame_deinit (&self->mpp_frame);
569 mpp_destroy (self->mpp_ctx);
570
571 gst_object_unref (self->allocator);
572
573 if (self->input_state)
574 gst_video_codec_state_unref (self->input_state);
575
576 GST_DEBUG_OBJECT (self, "stopped");
577
578 return TRUE;
579 }
580
581 static gboolean
gst_mpp_enc_flush(GstVideoEncoder * encoder)582 gst_mpp_enc_flush (GstVideoEncoder * encoder)
583 {
584 GST_DEBUG_OBJECT (encoder, "flushing");
585 gst_mpp_enc_reset (encoder, FALSE, FALSE);
586 return TRUE;
587 }
588
589 static gboolean
gst_mpp_enc_finish(GstVideoEncoder * encoder)590 gst_mpp_enc_finish (GstVideoEncoder * encoder)
591 {
592 GST_DEBUG_OBJECT (encoder, "finishing");
593 gst_mpp_enc_reset (encoder, TRUE, FALSE);
594 return GST_FLOW_OK;
595 }
596
597 static gboolean
gst_mpp_enc_set_format(GstVideoEncoder * encoder,GstVideoCodecState * state)598 gst_mpp_enc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
599 {
600 GstMppEnc *self = GST_MPP_ENC (encoder);
601 GstVideoInfo *info = &self->info;
602 MppFrameFormat format;
603 gint width, height, hstride, vstride;
604 gboolean convert = FALSE;
605
606 GST_DEBUG_OBJECT (self, "setting format: %" GST_PTR_FORMAT, state->caps);
607
608 if (self->input_state) {
609 if (gst_caps_is_strictly_equal (self->input_state->caps, state->caps))
610 return TRUE;
611
612 gst_mpp_enc_reset (encoder, TRUE, FALSE);
613
614 gst_video_codec_state_unref (self->input_state);
615 self->input_state = NULL;
616 }
617
618 self->input_state = gst_video_codec_state_ref (state);
619
620 *info = state->info;
621
622 if (!gst_mpp_enc_video_info_align (info))
623 return FALSE;
624
625 format = gst_mpp_gst_format_to_mpp_format (GST_VIDEO_INFO_FORMAT (info));
626 width = GST_VIDEO_INFO_WIDTH (info);
627 height = GST_VIDEO_INFO_HEIGHT (info);
628
629 if (self->rotation % 180)
630 SWAP (width, height);
631
632 width = self->width ? : width;
633 height = self->height ? : height;
634
635 /* Check for conversion */
636 if (self->rotation || !gst_mpp_enc_format_supported (format) ||
637 width != GST_VIDEO_INFO_WIDTH (info) ||
638 height != GST_VIDEO_INFO_HEIGHT (info)) {
639 if (!gst_mpp_use_rga ()) {
640 GST_ERROR_OBJECT (self, "unable to convert without RGA");
641 return FALSE;
642 }
643
644 convert = TRUE;
645 }
646
647 /* Check for alignment */
648 if (!gst_mpp_enc_video_info_matched (info, &state->info))
649 convert = TRUE;
650
651 if (convert) {
652 /* Prefer NV12 when using RGA conversion */
653 if (gst_mpp_use_rga ())
654 format = MPP_FMT_YUV420SP;
655
656 gst_mpp_video_info_update_format (info,
657 gst_mpp_mpp_format_to_gst_format (format), width, height);
658
659 if (!gst_mpp_enc_video_info_align (info))
660 return FALSE;
661
662 GST_INFO_OBJECT (self, "converting to aligned %s",
663 gst_mpp_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
664 }
665
666 hstride = GST_MPP_VIDEO_INFO_HSTRIDE (info);
667 vstride = GST_MPP_VIDEO_INFO_VSTRIDE (info);
668
669 GST_INFO_OBJECT (self, "applying %s%s %dx%d (%dx%d)",
670 gst_mpp_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)),
671 self->arm_afbc ? "(AFBC)" : "", width, height, hstride, vstride);
672
673 if (self->arm_afbc) {
674 if (self->mpp_type != MPP_VIDEO_CodingAVC &&
675 self->mpp_type != MPP_VIDEO_CodingHEVC) {
676 GST_WARNING_OBJECT (self, "Only H.264 and H.265 support ARM AFBC");
677 self->arm_afbc = FALSE;
678 } else {
679 format |= MPP_FRAME_FBC_AFBC_V2;
680 }
681 }
682
683 mpp_frame_set_fmt (self->mpp_frame, format);
684 mpp_frame_set_width (self->mpp_frame, width);
685 mpp_frame_set_height (self->mpp_frame, height);
686 mpp_frame_set_hor_stride (self->mpp_frame, hstride);
687 mpp_frame_set_ver_stride (self->mpp_frame, vstride);
688
689 if (!GST_VIDEO_INFO_FPS_N (info) || GST_VIDEO_INFO_FPS_N (info) > 240) {
690 GST_WARNING_OBJECT (self, "framerate (%d/%d) is insane!",
691 GST_VIDEO_INFO_FPS_N (info), GST_VIDEO_INFO_FPS_D (info));
692 GST_VIDEO_INFO_FPS_N (info) = DEFAULT_FPS;
693 }
694
695 mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:format", format);
696 mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:width", width);
697 mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:height", height);
698 mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:hor_stride",
699 GST_MPP_VIDEO_INFO_HSTRIDE (info));
700 mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:ver_stride",
701 GST_MPP_VIDEO_INFO_VSTRIDE (info));
702
703 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_in_flex", 0);
704 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_in_num",
705 GST_VIDEO_INFO_FPS_N (info));
706 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_in_denorm",
707 GST_VIDEO_INFO_FPS_D (info));
708 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_out_flex", 0);
709 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_out_num",
710 GST_VIDEO_INFO_FPS_N (info));
711 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_out_denorm",
712 GST_VIDEO_INFO_FPS_D (info));
713
714 return TRUE;
715 }
716
717 static gboolean
gst_mpp_enc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)718 gst_mpp_enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
719 {
720 GstMppEnc *self = GST_MPP_ENC (encoder);
721 GstStructure *config, *params;
722 GstVideoAlignment align;
723 GstBufferPool *pool;
724 GstVideoInfo info;
725 GstCaps *caps;
726 guint size;
727
728 GST_DEBUG_OBJECT (self, "propose allocation");
729
730 gst_query_parse_allocation (query, &caps, NULL);
731 if (caps == NULL)
732 return FALSE;
733
734 if (!gst_video_info_from_caps (&info, caps))
735 return FALSE;
736
737 gst_mpp_enc_video_info_align (&info);
738 size = GST_VIDEO_INFO_SIZE (&info);
739
740 gst_video_alignment_reset (&align);
741 align.padding_right = gst_mpp_get_pixel_stride (&info) -
742 GST_VIDEO_INFO_WIDTH (&info);
743 align.padding_bottom = GST_MPP_VIDEO_INFO_VSTRIDE (&info) -
744 GST_VIDEO_INFO_HEIGHT (&info);
745
746 /* Expose alignment to video-meta */
747 params = gst_structure_new ("video-meta",
748 "padding-top", G_TYPE_UINT, align.padding_top,
749 "padding-bottom", G_TYPE_UINT, align.padding_bottom,
750 "padding-left", G_TYPE_UINT, align.padding_left,
751 "padding-right", G_TYPE_UINT, align.padding_right, NULL);
752 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, params);
753 gst_structure_free (params);
754
755 pool = gst_video_buffer_pool_new ();
756
757 config = gst_buffer_pool_get_config (pool);
758 gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
759 gst_buffer_pool_config_set_allocator (config, self->allocator, NULL);
760
761 /* Expose alignment to pool */
762 gst_buffer_pool_config_add_option (config,
763 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
764 gst_buffer_pool_config_set_video_alignment (config, &align);
765
766 gst_buffer_pool_set_config (pool, config);
767
768 gst_query_add_allocation_pool (query, pool, size, MPP_PENDING_MAX, 0);
769 gst_query_add_allocation_param (query, self->allocator, NULL);
770
771 gst_object_unref (pool);
772
773 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
774 query);
775 }
776
777 static GstBuffer *
gst_mpp_enc_convert(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)778 gst_mpp_enc_convert (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
779 {
780 GstMppEnc *self = GST_MPP_ENC (encoder);
781 GstVideoInfo src_info = self->input_state->info;
782 GstVideoInfo *dst_info = &self->info;
783 GstVideoFrame src_frame, dst_frame;
784 GstBuffer *outbuf, *inbuf;
785 GstMemory *in_mem, *out_mem;
786 GstVideoMeta *meta;
787 gsize size, maxsize, offset;
788 guint i;
789
790 inbuf = frame->input_buffer;
791
792 meta = gst_buffer_get_video_meta (inbuf);
793 if (meta) {
794 for (i = 0; i < meta->n_planes; i++) {
795 GST_VIDEO_INFO_PLANE_STRIDE (&src_info, i) = meta->stride[i];
796 GST_VIDEO_INFO_PLANE_OFFSET (&src_info, i) = meta->offset[i];
797 }
798 }
799
800 size = gst_buffer_get_sizes (inbuf, &offset, &maxsize);
801 if (size < GST_VIDEO_INFO_SIZE (&src_info)) {
802 GST_ERROR_OBJECT (self, "input buffer too small (%" G_GSIZE_FORMAT
803 " < %" G_GSIZE_FORMAT ")", size, GST_VIDEO_INFO_SIZE (&src_info));
804 return NULL;
805 }
806
807 outbuf = gst_buffer_new ();
808 if (!outbuf)
809 goto err;
810
811 gst_buffer_copy_into (outbuf, inbuf,
812 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, 0);
813
814 gst_buffer_add_video_meta_full (outbuf, GST_VIDEO_FRAME_FLAG_NONE,
815 GST_VIDEO_INFO_FORMAT (dst_info),
816 GST_VIDEO_INFO_WIDTH (dst_info), GST_VIDEO_INFO_HEIGHT (dst_info),
817 GST_VIDEO_INFO_N_PLANES (dst_info), dst_info->offset, dst_info->stride);
818
819 if (self->rotation || !gst_mpp_enc_video_info_matched (&src_info, dst_info))
820 goto convert;
821
822 if (gst_buffer_n_memory (inbuf) != 1)
823 goto convert;
824
825 in_mem = gst_buffer_peek_memory (inbuf, 0);
826
827 out_mem = gst_mpp_allocator_import_gst_memory (self->allocator, in_mem);
828 if (!out_mem)
829 goto convert;
830
831 gst_buffer_append_memory (outbuf, out_mem);
832
833 /* Keep a ref of the original memory */
834 gst_buffer_append_memory (outbuf, gst_memory_ref (in_mem));
835
836 GST_DEBUG_OBJECT (self, "using imported buffer");
837 return outbuf;
838
839 convert:
840 out_mem = gst_allocator_alloc (self->allocator,
841 GST_VIDEO_INFO_SIZE (dst_info), NULL);
842 if (!out_mem)
843 goto err;
844
845 gst_buffer_append_memory (outbuf, out_mem);
846
847 #ifdef HAVE_RGA
848 if (gst_mpp_use_rga () &&
849 gst_mpp_rga_convert (inbuf, &src_info, out_mem, dst_info,
850 self->rotation)) {
851 GST_DEBUG_OBJECT (self, "using RGA converted buffer");
852 return outbuf;
853 }
854 #endif
855
856 if (self->rotation ||
857 GST_VIDEO_INFO_FORMAT (&src_info) != GST_VIDEO_INFO_FORMAT (dst_info))
858 goto err;
859
860 if (gst_video_frame_map (&src_frame, &src_info, inbuf, GST_MAP_READ)) {
861 if (gst_video_frame_map (&dst_frame, dst_info, outbuf, GST_MAP_WRITE)) {
862 if (!gst_video_frame_copy (&dst_frame, &src_frame)) {
863 gst_video_frame_unmap (&dst_frame);
864 gst_video_frame_unmap (&src_frame);
865 goto err;
866 }
867 gst_video_frame_unmap (&dst_frame);
868 }
869 gst_video_frame_unmap (&src_frame);
870 }
871
872 GST_DEBUG_OBJECT (self, "using software converted buffer");
873 return outbuf;
874 err:
875 if (outbuf)
876 gst_buffer_unref (outbuf);
877
878 GST_ERROR_OBJECT (self, "failed to convert frame");
879 return NULL;
880 }
881
882 static gboolean
gst_mpp_enc_force_keyframe(GstVideoEncoder * encoder,gboolean keyframe)883 gst_mpp_enc_force_keyframe (GstVideoEncoder * encoder, gboolean keyframe)
884 {
885 GstMppEnc *self = GST_MPP_ENC (encoder);
886
887 /* HACK: Use gop(1) to force keyframe */
888
889 if (!keyframe) {
890 self->prop_dirty = TRUE;
891 return gst_mpp_enc_apply_properties (encoder);
892 }
893
894 GST_INFO_OBJECT (self, "forcing keyframe");
895 mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:gop", 1);
896
897 if (self->mpi->control (self->mpp_ctx, MPP_ENC_SET_CFG, self->mpp_cfg)) {
898 GST_WARNING_OBJECT (self, "failed to set enc cfg");
899 return FALSE;
900 }
901
902 return TRUE;
903 }
904
905 static void
gst_mpp_enc_loop(GstVideoEncoder * encoder)906 gst_mpp_enc_loop (GstVideoEncoder * encoder)
907 {
908 GstMppEnc *self = GST_MPP_ENC (encoder);
909 GstVideoCodecFrame *frame;
910 GstBuffer *buffer;
911 GstMemory *mem;
912 MppFrame mframe;
913 MppPacket mpkt = NULL;
914 MppBuffer mbuf;
915 gboolean keyframe;
916 gint pkt_size;
917
918 GST_MPP_ENC_WAIT (encoder, self->pending_frames || self->flushing);
919
920 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
921
922 if (self->flushing && !self->pending_frames)
923 goto flushing;
924
925 frame = gst_video_encoder_get_oldest_frame (encoder);
926 self->pending_frames--;
927
928 GST_MPP_ENC_BROADCAST (encoder);
929
930 /* HACK: get the converted input buffer from frame->output_buffer */
931 mem = gst_buffer_peek_memory (frame->output_buffer, 0);
932 mbuf = gst_mpp_mpp_buffer_from_gst_memory (mem);
933
934 mframe = self->mpp_frame;
935 mpp_frame_set_buffer (mframe, mbuf);
936
937 keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
938 if (keyframe)
939 gst_mpp_enc_force_keyframe (encoder, TRUE);
940
941 /* Encode one frame */
942 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
943 if (!self->mpi->encode_put_frame (self->mpp_ctx, mframe))
944 self->mpi->encode_get_packet (self->mpp_ctx, &mpkt);
945 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
946
947 if (keyframe)
948 gst_mpp_enc_force_keyframe (encoder, FALSE);
949
950 if (!mpkt)
951 goto error;
952
953 pkt_size = mpp_packet_get_length (mpkt);
954
955 mbuf = mpp_packet_get_buffer (mpkt);
956
957 if (self->zero_copy_pkt) {
958 buffer = gst_buffer_new ();
959 if (!buffer)
960 goto error;
961
962 /* Allocated from the same DRM allocator in MPP */
963 mpp_buffer_set_index (mbuf, gst_mpp_allocator_get_index (self->allocator));
964
965 mem = gst_mpp_allocator_import_mppbuf (self->allocator, mbuf);
966 if (!mem) {
967 gst_buffer_unref (buffer);
968 goto error;
969 }
970
971 gst_memory_resize (mem, 0, pkt_size);
972 gst_buffer_append_memory (buffer, mem);
973 } else {
974 buffer = gst_video_encoder_allocate_output_buffer (encoder, pkt_size);
975 if (!buffer)
976 goto error;
977
978 gst_buffer_fill (buffer, 0, mpp_buffer_get_ptr (mbuf), pkt_size);
979 }
980
981 gst_buffer_replace (&frame->output_buffer, buffer);
982 gst_buffer_unref (buffer);
983
984 if (self->flushing && !self->draining)
985 goto drop;
986
987 GST_DEBUG_OBJECT (self, "finish frame ts=%" GST_TIME_FORMAT,
988 GST_TIME_ARGS (frame->pts));
989
990 gst_video_encoder_finish_frame (encoder, frame);
991
992 out:
993 if (mpkt)
994 mpp_packet_deinit (&mpkt);
995
996 if (self->task_ret != GST_FLOW_OK) {
997 GST_DEBUG_OBJECT (self, "leaving output thread: %s",
998 gst_flow_get_name (self->task_ret));
999
1000 gst_pad_pause_task (encoder->srcpad);
1001 }
1002
1003 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1004 return;
1005 flushing:
1006 GST_INFO_OBJECT (self, "flushing");
1007 self->task_ret = GST_FLOW_FLUSHING;
1008 goto out;
1009 error:
1010 GST_WARNING_OBJECT (self, "can't process this frame");
1011 goto drop;
1012 drop:
1013 GST_DEBUG_OBJECT (self, "drop frame");
1014 gst_buffer_replace (&frame->output_buffer, NULL);
1015 gst_video_encoder_finish_frame (encoder, frame);
1016 goto out;
1017 }
1018
1019 static GstFlowReturn
gst_mpp_enc_handle_frame(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)1020 gst_mpp_enc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
1021 {
1022 GstMppEnc *self = GST_MPP_ENC (encoder);
1023 GstBuffer *buffer;
1024 GstFlowReturn ret = GST_FLOW_OK;
1025
1026 GST_DEBUG_OBJECT (self, "handling frame %d", frame->system_frame_number);
1027
1028 GST_MPP_ENC_LOCK (encoder);
1029
1030 if (G_UNLIKELY (self->flushing))
1031 goto flushing;
1032
1033 if (G_UNLIKELY (!GST_MPP_ENC_TASK_STARTED (encoder))) {
1034 GST_DEBUG_OBJECT (self, "starting encoding thread");
1035
1036 gst_pad_start_task (encoder->srcpad,
1037 (GstTaskFunction) gst_mpp_enc_loop, encoder, NULL);
1038 }
1039
1040 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1041 buffer = gst_mpp_enc_convert (encoder, frame);
1042 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1043 if (G_UNLIKELY (!buffer))
1044 goto not_negotiated;
1045
1046 /* HACK: store the converted input buffer in frame->output_buffer */
1047 frame->output_buffer = buffer;
1048
1049 /* Avoid holding too much frames */
1050 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1051 GST_MPP_ENC_WAIT (encoder, self->pending_frames < MPP_PENDING_MAX
1052 || self->flushing);
1053 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1054
1055 self->pending_frames++;
1056
1057 GST_MPP_ENC_BROADCAST (encoder);
1058
1059 gst_video_codec_frame_unref (frame);
1060
1061 GST_MPP_ENC_UNLOCK (encoder);
1062
1063 return self->task_ret;
1064
1065 flushing:
1066 GST_WARNING_OBJECT (self, "flushing");
1067 ret = GST_FLOW_FLUSHING;
1068 goto drop;
1069 not_negotiated:
1070 GST_ERROR_OBJECT (self, "not negotiated");
1071 ret = GST_FLOW_NOT_NEGOTIATED;
1072 goto drop;
1073 drop:
1074 GST_WARNING_OBJECT (self, "can't handle this frame");
1075 gst_video_encoder_finish_frame (encoder, frame);
1076
1077 GST_MPP_ENC_UNLOCK (encoder);
1078
1079 return ret;
1080 }
1081
1082 static GstStateChangeReturn
gst_mpp_enc_change_state(GstElement * element,GstStateChange transition)1083 gst_mpp_enc_change_state (GstElement * element, GstStateChange transition)
1084 {
1085 GstVideoEncoder *encoder = GST_VIDEO_ENCODER (element);
1086
1087 if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
1088 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1089 gst_mpp_enc_reset (encoder, FALSE, TRUE);
1090 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1091 }
1092
1093 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1094 }
1095
1096 static void
gst_mpp_enc_init(GstMppEnc * self)1097 gst_mpp_enc_init (GstMppEnc * self)
1098 {
1099 self->mpp_type = MPP_VIDEO_CodingUnused;
1100
1101 self->header_mode = DEFAULT_PROP_HEADER_MODE;
1102 self->sei_mode = DEFAULT_PROP_SEI_MODE;
1103 self->rc_mode = DEFAULT_PROP_RC_MODE;
1104 self->rotation = DEFAULT_PROP_ROTATION;
1105 self->gop = DEFAULT_PROP_GOP;
1106 self->max_reenc = DEFAULT_PROP_MAX_REENC;
1107 self->bps = DEFAULT_PROP_BPS;
1108 self->bps_min = DEFAULT_PROP_BPS_MIN;
1109 self->bps_max = DEFAULT_PROP_BPS_MAX;
1110 self->zero_copy_pkt = DEFAULT_PROP_ZERO_COPY_PKT;
1111 self->arm_afbc = DEFAULT_PROP_ARM_AFBC;
1112 self->prop_dirty = TRUE;
1113 }
1114
1115 #define GST_TYPE_MPP_ENC_HEADER_MODE (gst_mpp_enc_header_mode_get_type ())
1116 static GType
gst_mpp_enc_header_mode_get_type(void)1117 gst_mpp_enc_header_mode_get_type (void)
1118 {
1119 static GType header_mode = 0;
1120
1121 if (!header_mode) {
1122 static const GEnumValue modes[] = {
1123 {MPP_ENC_HEADER_MODE_DEFAULT, "Only in the first frame", "first-frame"},
1124 {MPP_ENC_HEADER_MODE_EACH_IDR, "In every IDR frames", "each-idr"},
1125 {0, NULL, NULL}
1126 };
1127 header_mode = g_enum_register_static ("MppEncHeaderMode", modes);
1128 }
1129 return header_mode;
1130 }
1131
1132 #define GST_TYPE_MPP_ENC_SEI_MODE (gst_mpp_enc_sei_mode_get_type ())
1133 static GType
gst_mpp_enc_sei_mode_get_type(void)1134 gst_mpp_enc_sei_mode_get_type (void)
1135 {
1136 static GType sei_mode = 0;
1137
1138 if (!sei_mode) {
1139 static const GEnumValue modes[] = {
1140 {MPP_ENC_SEI_MODE_DISABLE, "SEI disabled", "disable"},
1141 {MPP_ENC_SEI_MODE_ONE_SEQ, "One SEI per sequence", "one-seq"},
1142 {MPP_ENC_SEI_MODE_ONE_FRAME, "One SEI per frame(if changed)",
1143 "one-frame"},
1144 {0, NULL, NULL}
1145 };
1146 sei_mode = g_enum_register_static ("GstMppEncSeiMode", modes);
1147 }
1148 return sei_mode;
1149 }
1150
1151 #define GST_TYPE_MPP_ENC_RC_MODE (gst_mpp_enc_rc_mode_get_type ())
1152 static GType
gst_mpp_enc_rc_mode_get_type(void)1153 gst_mpp_enc_rc_mode_get_type (void)
1154 {
1155 static GType rc_mode = 0;
1156
1157 if (!rc_mode) {
1158 static const GEnumValue modes[] = {
1159 {MPP_ENC_RC_MODE_VBR, "Variable bitrate", "vbr"},
1160 {MPP_ENC_RC_MODE_CBR, "Constant bitrate", "cbr"},
1161 {MPP_ENC_RC_MODE_FIXQP, "Fixed QP", "fixqp"},
1162 {0, NULL, NULL}
1163 };
1164 rc_mode = g_enum_register_static ("GstMppEncRcMode", modes);
1165 }
1166 return rc_mode;
1167 }
1168
1169 #ifdef HAVE_RGA
1170 #define GST_TYPE_MPP_ENC_ROTATION (gst_mpp_enc_rotation_get_type ())
1171 static GType
gst_mpp_enc_rotation_get_type(void)1172 gst_mpp_enc_rotation_get_type (void)
1173 {
1174 static GType rotation = 0;
1175
1176 if (!rotation) {
1177 static const GEnumValue rotations[] = {
1178 {0, "Rotate 0", "0"},
1179 {90, "Rotate 90", "90"},
1180 {180, "Rotate 180", "180"},
1181 {270, "Rotate 270", "270"},
1182 {0, NULL, NULL}
1183 };
1184 rotation = g_enum_register_static ("GstMppEncRotation", rotations);
1185 }
1186 return rotation;
1187 }
1188 #endif
1189
1190 static void
gst_mpp_enc_class_init(GstMppEncClass * klass)1191 gst_mpp_enc_class_init (GstMppEncClass * klass)
1192 {
1193 GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
1194 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1195 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1196
1197 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "mppenc", 0, "MPP encoder");
1198
1199 encoder_class->start = GST_DEBUG_FUNCPTR (gst_mpp_enc_start);
1200 encoder_class->stop = GST_DEBUG_FUNCPTR (gst_mpp_enc_stop);
1201 encoder_class->flush = GST_DEBUG_FUNCPTR (gst_mpp_enc_flush);
1202 encoder_class->finish = GST_DEBUG_FUNCPTR (gst_mpp_enc_finish);
1203 encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_mpp_enc_set_format);
1204 encoder_class->propose_allocation =
1205 GST_DEBUG_FUNCPTR (gst_mpp_enc_propose_allocation);
1206 encoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mpp_enc_handle_frame);
1207
1208 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_mpp_enc_set_property);
1209 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_mpp_enc_get_property);
1210
1211 g_object_class_install_property (gobject_class, PROP_HEADER_MODE,
1212 g_param_spec_enum ("header-mode", "Header mode",
1213 "Header mode",
1214 GST_TYPE_MPP_ENC_HEADER_MODE, DEFAULT_PROP_HEADER_MODE,
1215 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1216
1217 g_object_class_install_property (gobject_class, PROP_SEI_MODE,
1218 g_param_spec_enum ("sei-mode", "SEI mode",
1219 "SEI mode",
1220 GST_TYPE_MPP_ENC_SEI_MODE, DEFAULT_PROP_SEI_MODE,
1221 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1222
1223 g_object_class_install_property (gobject_class, PROP_RC_MODE,
1224 g_param_spec_enum ("rc-mode", "RC mode",
1225 "RC mode",
1226 GST_TYPE_MPP_ENC_RC_MODE, DEFAULT_PROP_RC_MODE,
1227 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1228
1229 #ifdef HAVE_RGA
1230 if (!gst_mpp_use_rga ())
1231 goto no_rga;
1232
1233 g_object_class_install_property (gobject_class, PROP_ROTATION,
1234 g_param_spec_enum ("rotation", "Rotation",
1235 "Rotation",
1236 GST_TYPE_MPP_ENC_ROTATION, DEFAULT_PROP_ROTATION,
1237 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1238
1239 g_object_class_install_property (gobject_class, PROP_WIDTH,
1240 g_param_spec_uint ("width", "Width",
1241 "Width (0 = original)",
1242 0, G_MAXINT, DEFAULT_PROP_WIDTH,
1243 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1244
1245 g_object_class_install_property (gobject_class, PROP_HEIGHT,
1246 g_param_spec_uint ("height", "Height",
1247 "Height (0 = original)",
1248 0, G_MAXINT, DEFAULT_PROP_HEIGHT,
1249 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1250
1251 no_rga:
1252 #endif
1253
1254 g_object_class_install_property (gobject_class, PROP_GOP,
1255 g_param_spec_int ("gop", "Group of pictures",
1256 "Group of pictures starting with I frame (-1 = FPS, 1 = all I frames)",
1257 -1, G_MAXINT, DEFAULT_PROP_GOP,
1258 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1259
1260 g_object_class_install_property (gobject_class, PROP_MAX_REENC,
1261 g_param_spec_uint ("max-reenc", "Max re-encode times",
1262 "Max re-encode times for one frame",
1263 0, 3, DEFAULT_PROP_MAX_REENC,
1264 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1265
1266 g_object_class_install_property (gobject_class, PROP_BPS,
1267 g_param_spec_uint ("bps", "Target BPS",
1268 "Target BPS (0 = auto calculate)",
1269 0, G_MAXINT, DEFAULT_PROP_BPS,
1270 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1271
1272 g_object_class_install_property (gobject_class, PROP_BPS_MIN,
1273 g_param_spec_uint ("bps-min", "Min BPS",
1274 "Min BPS (0 = auto calculate)",
1275 0, G_MAXINT, DEFAULT_PROP_BPS_MIN,
1276 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1277
1278 g_object_class_install_property (gobject_class, PROP_BPS_MAX,
1279 g_param_spec_uint ("bps-max", "Max BPS",
1280 "Max BPS (0 = auto calculate)",
1281 0, G_MAXINT, DEFAULT_PROP_BPS_MAX,
1282 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1283
1284 g_object_class_install_property (gobject_class, PROP_ZERO_COPY_PKT,
1285 g_param_spec_boolean ("zero-copy-pkt", "Zero-copy encoded packet",
1286 "Zero-copy encoded packet", DEFAULT_PROP_ZERO_COPY_PKT,
1287 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1288
1289 if (g_getenv ("GST_MPPENC_DEFAULT_ARM_AFBC"))
1290 DEFAULT_PROP_ARM_AFBC = TRUE;
1291
1292 g_object_class_install_property (gobject_class, PROP_ARM_AFBC,
1293 g_param_spec_boolean ("arm-afbc", "ARM AFBC",
1294 "Input is ARM AFBC compressed format", DEFAULT_PROP_ARM_AFBC,
1295 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1296
1297 element_class->change_state = GST_DEBUG_FUNCPTR (gst_mpp_enc_change_state);
1298 }
1299