xref: /OK3568_Linux_fs/external/gstreamer-rockchip/gst/rockchipmpp/gstmpph265enc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright 2021 Rockchip Electronics Co., Ltd
3  *     Author: Jeffy Chen <jeffy.chen@rock-chips.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <string.h>
27 
28 #include "gstmpph265enc.h"
29 
30 /* FIXME: Not all chips support NV24 and Y444. */
31 #define MPP_H265_ENC_FORMATS MPP_ENC_FORMATS ", NV24, Y444"
32 
33 #define GST_MPP_H265_ENC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
34     GST_TYPE_MPP_H265_ENC, GstMppH265Enc))
35 
36 #define GST_CAT_DEFAULT mpp_h265_enc_debug
37 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
38 
39 struct _GstMppH265Enc
40 {
41   GstMppEnc parent;
42 
43   guint qp_init;
44   guint qp_min;
45   guint qp_max;
46   gint qp_max_step;
47 };
48 
49 #define parent_class gst_mpp_h265_enc_parent_class
50 G_DEFINE_TYPE (GstMppH265Enc, gst_mpp_h265_enc, GST_TYPE_MPP_ENC);
51 
52 #define DEFAULT_PROP_QP_INIT 26
53 #define DEFAULT_PROP_QP_MIN 0   /* Auto */
54 #define DEFAULT_PROP_QP_MAX 0   /* Auto */
55 #define DEFAULT_PROP_QP_MAX_STEP -1     /* Auto */
56 
57 enum
58 {
59   PROP_0,
60   PROP_QP_INIT,
61   PROP_QP_MIN,
62   PROP_QP_MAX,
63   PROP_QP_MAX_STEP,
64   PROP_LAST,
65 };
66 
67 #define GST_MPP_H265_ENC_SIZE_CAPS \
68     "width  = (int) [ 96, MAX ], height = (int) [ 64, MAX ]"
69 
70 static GstStaticPadTemplate gst_mpp_h265_enc_src_template =
71 GST_STATIC_PAD_TEMPLATE ("src",
72     GST_PAD_SRC,
73     GST_PAD_ALWAYS,
74     GST_STATIC_CAPS ("video/x-h265, "
75         GST_MPP_H265_ENC_SIZE_CAPS ","
76         "stream-format = (string) { byte-stream }, "
77         "alignment = (string) { au }")
78     );
79 
80 static GstStaticPadTemplate gst_mpp_h265_enc_sink_template =
81     GST_STATIC_PAD_TEMPLATE ("sink",
82     GST_PAD_SINK,
83     GST_PAD_ALWAYS,
84     GST_STATIC_CAPS ("video/x-raw,"
85         "format = (string) { " MPP_H265_ENC_FORMATS " }, "
86         GST_MPP_H265_ENC_SIZE_CAPS ";"));
87 
88 static void
gst_mpp_h265_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)89 gst_mpp_h265_enc_set_property (GObject * object,
90     guint prop_id, const GValue * value, GParamSpec * pspec)
91 {
92   GstVideoEncoder *encoder = GST_VIDEO_ENCODER (object);
93   GstMppH265Enc *self = GST_MPP_H265_ENC (encoder);
94   GstMppEnc *mppenc = GST_MPP_ENC (encoder);
95 
96   switch (prop_id) {
97     case PROP_QP_INIT:{
98       guint qp_init = g_value_get_uint (value);
99       if (self->qp_init == qp_init)
100         return;
101 
102       self->qp_init = qp_init;
103       break;
104     }
105     case PROP_QP_MIN:{
106       guint qp_min = g_value_get_uint (value);
107       if (self->qp_min == qp_min)
108         return;
109 
110       self->qp_min = qp_min;
111       break;
112     }
113     case PROP_QP_MAX:{
114       guint qp_max = g_value_get_uint (value);
115       if (self->qp_max == qp_max)
116         return;
117 
118       self->qp_max = qp_max;
119       break;
120     }
121     case PROP_QP_MAX_STEP:{
122       gint qp_max_step = g_value_get_int (value);
123       if (self->qp_max_step == qp_max_step)
124         return;
125 
126       self->qp_max_step = qp_max_step;
127       break;
128     }
129     default:
130       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
131       return;
132   }
133 
134   mppenc->prop_dirty = TRUE;
135 }
136 
137 static void
gst_mpp_h265_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)138 gst_mpp_h265_enc_get_property (GObject * object,
139     guint prop_id, GValue * value, GParamSpec * pspec)
140 {
141   GstVideoEncoder *encoder = GST_VIDEO_ENCODER (object);
142   GstMppH265Enc *self = GST_MPP_H265_ENC (encoder);
143 
144   switch (prop_id) {
145     case PROP_QP_INIT:
146       g_value_set_uint (value, self->qp_init);
147       break;
148     case PROP_QP_MIN:
149       g_value_set_uint (value, self->qp_min);
150       break;
151     case PROP_QP_MAX:
152       g_value_set_uint (value, self->qp_max);
153       break;
154     case PROP_QP_MAX_STEP:
155       g_value_set_int (value, self->qp_max_step);
156       break;
157     default:
158       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
159       break;
160   }
161 }
162 
163 static gboolean
gst_mpp_h265_enc_set_src_caps(GstVideoEncoder * encoder)164 gst_mpp_h265_enc_set_src_caps (GstVideoEncoder * encoder)
165 {
166   GstStructure *structure;
167   GstCaps *caps;
168 
169   caps = gst_caps_new_empty_simple ("video/x-h265");
170 
171   structure = gst_caps_get_structure (caps, 0);
172   gst_structure_set (structure, "stream-format",
173       G_TYPE_STRING, "byte-stream", NULL);
174   gst_structure_set (structure, "alignment", G_TYPE_STRING, "au", NULL);
175 
176   return gst_mpp_enc_set_src_caps (encoder, caps);
177 }
178 
179 static gboolean
gst_mpp_h265_enc_apply_properties(GstVideoEncoder * encoder)180 gst_mpp_h265_enc_apply_properties (GstVideoEncoder * encoder)
181 {
182   GstMppH265Enc *self = GST_MPP_H265_ENC (encoder);
183   GstMppEnc *mppenc = GST_MPP_ENC (encoder);
184 
185   if (G_LIKELY (!mppenc->prop_dirty))
186     return TRUE;
187 
188   mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_init", self->qp_init);
189 
190   if (mppenc->rc_mode == MPP_ENC_RC_MODE_FIXQP) {
191     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_max", self->qp_init);
192     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_min", self->qp_init);
193     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_step", 0);
194   } else if (mppenc->rc_mode == MPP_ENC_RC_MODE_CBR) {
195     /* NOTE: These settings have been tuned for better quality */
196     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_max",
197         self->qp_max ? self->qp_max : 28);
198     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_min",
199         self->qp_min ? self->qp_min : 4);
200     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_step",
201         self->qp_max_step >= 0 ? self->qp_max_step : 8);
202   } else if (mppenc->rc_mode == MPP_ENC_RC_MODE_VBR) {
203     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_max",
204         self->qp_max ? self->qp_max : 40);
205     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_min",
206         self->qp_min ? self->qp_min : 12);
207     mpp_enc_cfg_set_s32 (mppenc->mpp_cfg, "h265:qp_step",
208         self->qp_max_step >= 0 ? self->qp_max_step : 8);
209   }
210 
211   if (!gst_mpp_enc_apply_properties (encoder))
212     return FALSE;
213 
214   return gst_mpp_h265_enc_set_src_caps (encoder);
215 }
216 
217 static gboolean
gst_mpp_h265_enc_set_format(GstVideoEncoder * encoder,GstVideoCodecState * state)218 gst_mpp_h265_enc_set_format (GstVideoEncoder * encoder,
219     GstVideoCodecState * state)
220 {
221   GstVideoEncoderClass *pclass = GST_VIDEO_ENCODER_CLASS (parent_class);
222 
223   if (!pclass->set_format (encoder, state))
224     return FALSE;
225 
226   return gst_mpp_h265_enc_apply_properties (encoder);
227 }
228 
229 static GstFlowReturn
gst_mpp_h265_enc_handle_frame(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)230 gst_mpp_h265_enc_handle_frame (GstVideoEncoder * encoder,
231     GstVideoCodecFrame * frame)
232 {
233   GstVideoEncoderClass *pclass = GST_VIDEO_ENCODER_CLASS (parent_class);
234 
235   if (G_UNLIKELY (!gst_mpp_h265_enc_apply_properties (encoder))) {
236     gst_video_codec_frame_unref (frame);
237     return GST_FLOW_NOT_NEGOTIATED;
238   }
239 
240   return pclass->handle_frame (encoder, frame);
241 }
242 
243 static void
gst_mpp_h265_enc_init(GstMppH265Enc * self)244 gst_mpp_h265_enc_init (GstMppH265Enc * self)
245 {
246   self->parent.mpp_type = MPP_VIDEO_CodingHEVC;
247 
248   self->qp_init = DEFAULT_PROP_QP_INIT;
249   self->qp_min = DEFAULT_PROP_QP_MIN;
250   self->qp_max = DEFAULT_PROP_QP_MAX;
251   self->qp_max_step = DEFAULT_PROP_QP_MAX_STEP;
252 }
253 
254 static void
gst_mpp_h265_enc_class_init(GstMppH265EncClass * klass)255 gst_mpp_h265_enc_class_init (GstMppH265EncClass * klass)
256 {
257   GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
258   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
259   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
260 
261   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "mpph265enc", 0,
262       "MPP H265 encoder");
263 
264   encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_mpp_h265_enc_set_format);
265   encoder_class->handle_frame =
266       GST_DEBUG_FUNCPTR (gst_mpp_h265_enc_handle_frame);
267 
268   gobject_class->set_property =
269       GST_DEBUG_FUNCPTR (gst_mpp_h265_enc_set_property);
270   gobject_class->get_property =
271       GST_DEBUG_FUNCPTR (gst_mpp_h265_enc_get_property);
272 
273   g_object_class_install_property (gobject_class, PROP_QP_INIT,
274       g_param_spec_uint ("qp-init", "Initial QP",
275           "Initial QP (lower value means higher quality)",
276           0, 51, DEFAULT_PROP_QP_INIT,
277           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
278 
279   g_object_class_install_property (gobject_class, PROP_QP_MIN,
280       g_param_spec_uint ("qp-min", "Min QP",
281           "Min QP (0 = default)", 0, 51, DEFAULT_PROP_QP_MIN,
282           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
283 
284   g_object_class_install_property (gobject_class, PROP_QP_MAX,
285       g_param_spec_uint ("qp-max", "Max QP",
286           "Max QP (0 = default)", 0, 51, DEFAULT_PROP_QP_MAX,
287           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
288 
289   g_object_class_install_property (gobject_class, PROP_QP_MAX_STEP,
290       g_param_spec_int ("qp-max-step", "Max QP step",
291           "Max delta QP step between two frames (-1 = default)", -1, 51,
292           DEFAULT_PROP_QP_MAX_STEP,
293           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
294 
295   gst_element_class_add_pad_template (element_class,
296       gst_static_pad_template_get (&gst_mpp_h265_enc_src_template));
297 
298   gst_element_class_add_pad_template (element_class,
299       gst_static_pad_template_get (&gst_mpp_h265_enc_sink_template));
300 
301   gst_element_class_set_static_metadata (element_class,
302       "Rockchip Mpp H265 Encoder", "Codec/Encoder/Video",
303       "Encode video streams via Rockchip Mpp",
304       "Jeffy Chen <jeffy.chen@rock-chips.com>");
305 }
306 
307 gboolean
gst_mpp_h265_enc_register(GstPlugin * plugin,guint rank)308 gst_mpp_h265_enc_register (GstPlugin * plugin, guint rank)
309 {
310   if (!gst_mpp_enc_supported (MPP_VIDEO_CodingHEVC))
311     return FALSE;
312 
313   return gst_element_register (plugin, "mpph265enc", rank,
314       gst_mpp_h265_enc_get_type ());
315 }
316