xref: /OK3568_Linux_fs/external/gstreamer-rockchip/gst/rockchipmpp/gstmpph264enc.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 "gstmpph264enc.h"
32 
33 /* FIXME: Not all chips support NV24 and Y444. */
34 #define MPP_H264_ENC_FORMATS MPP_ENC_FORMATS ", NV24, Y444"
35 
36 #define GST_MPP_H264_ENC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
37     GST_TYPE_MPP_H264_ENC, GstMppH264Enc))
38 
39 #define GST_CAT_DEFAULT mpp_h264_enc_debug
40 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
41 
42 typedef enum
43 {
44   GST_MPP_H264_PROFILE_BASELINE = 66,
45   GST_MPP_H264_PROFILE_MAIN = 77,
46   GST_MPP_H264_PROFILE_HIGH = 100,
47 } GstMppH264Profile;
48 
49 struct _GstMppH264Enc
50 {
51   GstMppEnc parent;
52 
53   GstMppH264Profile profile;
54   gint level;
55 
56   guint qp_init;
57   guint qp_min;
58   guint qp_max;
59   gint qp_max_step;
60 };
61 
62 #define parent_class gst_mpp_h264_enc_parent_class
63 G_DEFINE_TYPE (GstMppH264Enc, gst_mpp_h264_enc, GST_TYPE_MPP_ENC);
64 
65 #define DEFAULT_PROP_LEVEL 40   /* 1080p@30fps */
66 #define DEFAULT_PROP_PROFILE GST_MPP_H264_PROFILE_HIGH
67 #define DEFAULT_PROP_QP_INIT 26
68 #define DEFAULT_PROP_QP_MIN 0   /* Auto */
69 #define DEFAULT_PROP_QP_MAX 0   /* Auto */
70 #define DEFAULT_PROP_QP_MAX_STEP -1     /* Auto */
71 
72 enum
73 {
74   PROP_0,
75   PROP_PROFILE,
76   PROP_LEVEL,
77   PROP_QP_INIT,
78   PROP_QP_MIN,
79   PROP_QP_MAX,
80   PROP_QP_MAX_STEP,
81   PROP_LAST,
82 };
83 
84 #define GST_MPP_H264_ENC_SIZE_CAPS \
85     "width  = (int) [ 96, MAX ], height = (int) [ 64, MAX ]"
86 
87 static GstStaticPadTemplate gst_mpp_h264_enc_src_template =
88 GST_STATIC_PAD_TEMPLATE ("src",
89     GST_PAD_SRC,
90     GST_PAD_ALWAYS,
91     GST_STATIC_CAPS ("video/x-h264, "
92         GST_MPP_H264_ENC_SIZE_CAPS ","
93         "stream-format = (string) { byte-stream }, "
94         "alignment = (string) { au }, "
95         "profile = (string) { baseline, main, high }"));
96 
97 static GstStaticPadTemplate gst_mpp_h264_enc_sink_template =
98 GST_STATIC_PAD_TEMPLATE ("sink",
99     GST_PAD_SINK,
100     GST_PAD_ALWAYS,
101     GST_STATIC_CAPS ("video/x-raw,"
102         "format = (string) { " MPP_H264_ENC_FORMATS " }, "
103         GST_MPP_H264_ENC_SIZE_CAPS));
104 
105 #define GST_TYPE_MPP_H264_ENC_PROFILE (gst_mpp_h264_enc_profile_get_type ())
106 static GType
gst_mpp_h264_enc_profile_get_type(void)107 gst_mpp_h264_enc_profile_get_type (void)
108 {
109   static GType profile = 0;
110 
111   if (!profile) {
112     static const GEnumValue profiles[] = {
113       {GST_MPP_H264_PROFILE_BASELINE, "Baseline", "baseline"},
114       {GST_MPP_H264_PROFILE_MAIN, "Main", "main"},
115       {GST_MPP_H264_PROFILE_HIGH, "High", "high"},
116       {0, NULL, NULL},
117     };
118     profile = g_enum_register_static ("GstMppH264Profile", profiles);
119   }
120   return profile;
121 }
122 
123 #define GST_TYPE_MPP_H264_ENC_LEVEL (gst_mpp_h264_enc_level_get_type ())
124 static GType
gst_mpp_h264_enc_level_get_type(void)125 gst_mpp_h264_enc_level_get_type (void)
126 {
127   static GType level = 0;
128 
129   if (!level) {
130     static const GEnumValue levels[] = {
131       {10, "1", "1"},
132       {99, "1b", "1b"},
133       {11, "1.1", "1.1"},
134       {12, "1.2", "1.2"},
135       {13, "1.3", "1.3"},
136       {20, "2", "2"},
137       {21, "2.1", "2.1"},
138       {22, "2.2", "2.2"},
139       {30, "3", "3"},
140       {31, "3.1", "3.1"},
141       {32, "3.2", "3.2"},
142       {40, "4", "4"},
143       {41, "4.1", "4.1"},
144       {42, "4.2", "4.2"},
145       {50, "5", "5"},
146       {51, "5.1", "5.1"},
147       {52, "5.2", "5.2"},
148       {60, "6", "6"},
149       {61, "6.1", "6.1"},
150       {62, "6.2", "6.2"},
151       {0, NULL, NULL},
152     };
153     level = g_enum_register_static ("GstMppH264Level", levels);
154   }
155   return level;
156 }
157 
158 static void
gst_mpp_h264_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)159 gst_mpp_h264_enc_set_property (GObject * object,
160     guint prop_id, const GValue * value, GParamSpec * pspec)
161 {
162   GstVideoEncoder *encoder = GST_VIDEO_ENCODER (object);
163   GstMppH264Enc *self = GST_MPP_H264_ENC (encoder);
164   GstMppEnc *mppenc = GST_MPP_ENC (encoder);
165 
166   switch (prop_id) {
167     case PROP_PROFILE:{
168       GstMppH264Profile profile = g_value_get_enum (value);
169       if (self->profile == profile)
170         return;
171 
172       self->profile = profile;
173       break;
174     }
175     case PROP_LEVEL:{
176       gint level = g_value_get_enum (value);
177       if (self->level == level)
178         return;
179 
180       self->level = level;
181       break;
182     }
183     case PROP_QP_INIT:{
184       guint qp_init = g_value_get_uint (value);
185       if (self->qp_init == qp_init)
186         return;
187 
188       self->qp_init = qp_init;
189       break;
190     }
191     case PROP_QP_MIN:{
192       guint qp_min = g_value_get_uint (value);
193       if (self->qp_min == qp_min)
194         return;
195 
196       self->qp_min = qp_min;
197       break;
198     }
199     case PROP_QP_MAX:{
200       guint qp_max = g_value_get_uint (value);
201       if (self->qp_max == qp_max)
202         return;
203 
204       self->qp_max = qp_max;
205       break;
206     }
207     case PROP_QP_MAX_STEP:{
208       gint qp_max_step = g_value_get_int (value);
209       if (self->qp_max_step == qp_max_step)
210         return;
211 
212       self->qp_max_step = qp_max_step;
213       break;
214     }
215     default:
216       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
217       return;
218   }
219 
220   mppenc->prop_dirty = TRUE;
221 }
222 
223 static void
gst_mpp_h264_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)224 gst_mpp_h264_enc_get_property (GObject * object,
225     guint prop_id, GValue * value, GParamSpec * pspec)
226 {
227   GstVideoEncoder *encoder = GST_VIDEO_ENCODER (object);
228   GstMppH264Enc *self = GST_MPP_H264_ENC (encoder);
229 
230   switch (prop_id) {
231     case PROP_PROFILE:
232       g_value_set_enum (value, self->profile);
233       break;
234     case PROP_LEVEL:
235       g_value_set_enum (value, self->level);
236       break;
237     case PROP_QP_INIT:
238       g_value_set_uint (value, self->qp_init);
239       break;
240     case PROP_QP_MIN:
241       g_value_set_uint (value, self->qp_min);
242       break;
243     case PROP_QP_MAX:
244       g_value_set_uint (value, self->qp_max);
245       break;
246     case PROP_QP_MAX_STEP:
247       g_value_set_int (value, self->qp_max_step);
248       break;
249     default:
250       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
251       break;
252   }
253 }
254 
255 static gboolean
gst_mpp_h264_enc_set_src_caps(GstVideoEncoder * encoder)256 gst_mpp_h264_enc_set_src_caps (GstVideoEncoder * encoder)
257 {
258   GstMppH264Enc *self = GST_MPP_H264_ENC (encoder);
259   GstStructure *structure;
260   GstCaps *caps;
261   gchar *string;
262 
263   caps = gst_caps_new_empty_simple ("video/x-h264");
264 
265   structure = gst_caps_get_structure (caps, 0);
266   gst_structure_set (structure, "stream-format",
267       G_TYPE_STRING, "byte-stream", NULL);
268   gst_structure_set (structure, "alignment", G_TYPE_STRING, "au", NULL);
269 
270   string = g_enum_to_string (GST_TYPE_MPP_H264_ENC_PROFILE, self->profile);
271   gst_structure_set (structure, "profile", G_TYPE_STRING, string, NULL);
272   g_free (string);
273 
274   string = g_enum_to_string (GST_TYPE_MPP_H264_ENC_LEVEL, self->level);
275   gst_structure_set (structure, "level", G_TYPE_STRING, string, NULL);
276   g_free (string);
277 
278   return gst_mpp_enc_set_src_caps (encoder, caps);
279 }
280 
281 static gboolean
gst_mpp_h264_enc_apply_properties(GstVideoEncoder * encoder)282 gst_mpp_h264_enc_apply_properties (GstVideoEncoder * encoder)
283 {
284   GstMppH264Enc *self = GST_MPP_H264_ENC (encoder);
285   GstMppEnc *mppenc = GST_MPP_ENC (encoder);
286 
287   if (G_LIKELY (!mppenc->prop_dirty))
288     return TRUE;
289 
290   mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_init", self->qp_init);
291 
292   if (mppenc->rc_mode == MPP_ENC_RC_MODE_FIXQP) {
293     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_max", self->qp_init);
294     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_min", self->qp_init);
295     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_step", 0);
296   } else if (mppenc->rc_mode == MPP_ENC_RC_MODE_CBR) {
297     /* NOTE: These settings have been tuned for better quality */
298     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_max",
299         self->qp_max ? self->qp_max : 28);
300     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_min",
301         self->qp_min ? self->qp_min : 4);
302     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_step",
303         self->qp_max_step >= 0 ? self->qp_max_step : 8);
304   } else if (mppenc->rc_mode == MPP_ENC_RC_MODE_VBR) {
305     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_max",
306         self->qp_max ? self->qp_max : 40);
307     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_min",
308         self->qp_min ? self->qp_min : 12);
309     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:qp_step",
310         self->qp_max_step >= 0 ? self->qp_max_step : 8);
311   }
312 
313   mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:profile", self->profile);
314   mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:level", self->level);
315 
316   mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:trans8x8",
317       self->profile == GST_MPP_H264_PROFILE_HIGH);
318   mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:cabac_en",
319       self->profile != GST_MPP_H264_PROFILE_BASELINE);
320   mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h264:cabac_idc", 0);
321 
322   if (!gst_mpp_enc_apply_properties (encoder))
323     return FALSE;
324 
325   return gst_mpp_h264_enc_set_src_caps (encoder);
326 }
327 
328 static gboolean
gst_mpp_h264_enc_set_format(GstVideoEncoder * encoder,GstVideoCodecState * state)329 gst_mpp_h264_enc_set_format (GstVideoEncoder * encoder,
330     GstVideoCodecState * state)
331 {
332   GstVideoEncoderClass *pclass = GST_VIDEO_ENCODER_CLASS (parent_class);
333 
334   if (!pclass->set_format (encoder, state))
335     return FALSE;
336 
337   return gst_mpp_h264_enc_apply_properties (encoder);
338 }
339 
340 static GstFlowReturn
gst_mpp_h264_enc_handle_frame(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)341 gst_mpp_h264_enc_handle_frame (GstVideoEncoder * encoder,
342     GstVideoCodecFrame * frame)
343 {
344   GstVideoEncoderClass *pclass = GST_VIDEO_ENCODER_CLASS (parent_class);
345 
346   if (G_UNLIKELY (!gst_mpp_h264_enc_apply_properties (encoder))) {
347     gst_video_codec_frame_unref (frame);
348     return GST_FLOW_NOT_NEGOTIATED;
349   }
350 
351   return pclass->handle_frame (encoder, frame);
352 }
353 
354 static void
gst_mpp_h264_enc_init(GstMppH264Enc * self)355 gst_mpp_h264_enc_init (GstMppH264Enc * self)
356 {
357   self->parent.mpp_type = MPP_VIDEO_CodingAVC;
358 
359   self->profile = DEFAULT_PROP_PROFILE;
360   self->level = DEFAULT_PROP_LEVEL;
361   self->qp_init = DEFAULT_PROP_QP_INIT;
362   self->qp_min = DEFAULT_PROP_QP_MIN;
363   self->qp_max = DEFAULT_PROP_QP_MAX;
364   self->qp_max_step = DEFAULT_PROP_QP_MAX_STEP;
365 }
366 
367 static void
gst_mpp_h264_enc_class_init(GstMppH264EncClass * klass)368 gst_mpp_h264_enc_class_init (GstMppH264EncClass * klass)
369 {
370   GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
371   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
372   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
373 
374   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "mpph264enc", 0,
375       "MPP H264 encoder");
376 
377   encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_mpp_h264_enc_set_format);
378   encoder_class->handle_frame =
379       GST_DEBUG_FUNCPTR (gst_mpp_h264_enc_handle_frame);
380 
381   gobject_class->set_property =
382       GST_DEBUG_FUNCPTR (gst_mpp_h264_enc_set_property);
383   gobject_class->get_property =
384       GST_DEBUG_FUNCPTR (gst_mpp_h264_enc_get_property);
385 
386   g_object_class_install_property (gobject_class, PROP_PROFILE,
387       g_param_spec_enum ("profile", "H264 profile",
388           "H264 profile",
389           GST_TYPE_MPP_H264_ENC_PROFILE, DEFAULT_PROP_PROFILE,
390           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
391 
392   g_object_class_install_property (gobject_class, PROP_LEVEL,
393       g_param_spec_enum ("level", "H264 level",
394           "H264 level (40~41 = 1080p@30fps, 42 = 1080p60fps, 50~52 = 4K@30fps)",
395           GST_TYPE_MPP_H264_ENC_LEVEL, DEFAULT_PROP_LEVEL,
396           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
397 
398   g_object_class_install_property (gobject_class, PROP_QP_INIT,
399       g_param_spec_uint ("qp-init", "Initial QP",
400           "Initial QP (lower value means higher quality)",
401           0, 51, DEFAULT_PROP_QP_INIT,
402           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
403 
404   g_object_class_install_property (gobject_class, PROP_QP_MIN,
405       g_param_spec_uint ("qp-min", "Min QP",
406           "Min QP (0 = default)", 0, 51, DEFAULT_PROP_QP_MIN,
407           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
408 
409   g_object_class_install_property (gobject_class, PROP_QP_MAX,
410       g_param_spec_uint ("qp-max", "Max QP",
411           "Max QP (0 = default)", 0, 51, DEFAULT_PROP_QP_MAX,
412           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
413 
414   g_object_class_install_property (gobject_class, PROP_QP_MAX_STEP,
415       g_param_spec_int ("qp-max-step", "Max QP step",
416           "Max delta QP step between two frames (-1 = default)", -1, 51,
417           DEFAULT_PROP_QP_MAX_STEP,
418           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
419 
420   gst_element_class_add_pad_template (element_class,
421       gst_static_pad_template_get (&gst_mpp_h264_enc_src_template));
422 
423   gst_element_class_add_pad_template (element_class,
424       gst_static_pad_template_get (&gst_mpp_h264_enc_sink_template));
425 
426   gst_element_class_set_static_metadata (element_class,
427       "Rockchip Mpp H264 Encoder", "Codec/Encoder/Video",
428       "Encode video streams via Rockchip Mpp",
429       "Randy Li <randy.li@rock-chips.com>, "
430       "Jeffy Chen <jeffy.chen@rock-chips.com>");
431 }
432 
433 gboolean
gst_mpp_h264_enc_register(GstPlugin * plugin,guint rank)434 gst_mpp_h264_enc_register (GstPlugin * plugin, guint rank)
435 {
436   if (!gst_mpp_enc_supported (MPP_VIDEO_CodingAVC))
437     return FALSE;
438 
439   return gst_element_register (plugin, "mpph264enc", rank,
440       gst_mpp_h264_enc_get_type ());
441 }
442