xref: /OK3568_Linux_fs/external/gstreamer-rockchip/gst/rockchipmpp/gstmppenc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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