xref: /OK3568_Linux_fs/external/gstreamer-rockchip/gst/rockchipmpp/gstmppvideodec.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 "gstmppvideodec.h"
30 
31 #define GST_MPP_VIDEO_DEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
32     GST_TYPE_MPP_VIDEO_DEC, GstMppVideoDec))
33 
34 #define GST_CAT_DEFAULT mpp_video_dec_debug
35 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
36 
37 struct _GstMppVideoDec
38 {
39   GstMppDec parent;
40 
41   gint poll_timeout;
42 };
43 
44 #define parent_class gst_mpp_video_dec_parent_class
45 G_DEFINE_TYPE (GstMppVideoDec, gst_mpp_video_dec, GST_TYPE_MPP_DEC);
46 
47 /* Default output format is auto */
48 static GstVideoFormat DEFAULT_PROP_FORMAT = GST_VIDEO_FORMAT_UNKNOWN;
49 /* Disable ARM AFBC by default */
50 static GstVideoFormat DEFAULT_PROP_ARM_AFBC = FALSE;
51 
52 enum
53 {
54   PROP_0,
55   PROP_FORMAT,
56   PROP_ARM_AFBC,
57   PROP_LAST,
58 };
59 
60 /* GstVideoDecoder base class method */
61 static GstStaticPadTemplate gst_mpp_video_dec_sink_template =
62     GST_STATIC_PAD_TEMPLATE ("sink",
63     GST_PAD_SINK,
64     GST_PAD_ALWAYS,
65     GST_STATIC_CAPS ("video/x-h263, parsed = (boolean) true;"
66         "video/x-h264, parsed = (boolean) true;"
67         "video/x-h265, parsed = (boolean) true;"
68         "video/x-av1, parsed = (boolean) true;"
69         "video/x-vp8; video/x-vp9;"
70         "video/mpeg, parsed = (boolean) true,"
71         "mpegversion = (int) { 1, 2, 4 }, systemstream = (boolean) false;"));
72 
73 static GstStaticPadTemplate gst_mpp_video_dec_src_template =
74     GST_STATIC_PAD_TEMPLATE ("src",
75     GST_PAD_SRC,
76     GST_PAD_ALWAYS,
77     GST_STATIC_CAPS (MPP_DEC_CAPS_MAKE ("{" MPP_DEC_FORMATS "}") ";"
78         MPP_DEC_CAPS_MAKE_AFBC ("{" MPP_DEC_FORMATS "}") ";")
79     );
80 
81 static MppCodingType
gst_mpp_video_dec_get_mpp_type(GstStructure * s)82 gst_mpp_video_dec_get_mpp_type (GstStructure * s)
83 {
84   if (gst_structure_has_name (s, "video/x-h263"))
85     return MPP_VIDEO_CodingH263;
86 
87   if (gst_structure_has_name (s, "video/x-h264"))
88     return MPP_VIDEO_CodingAVC;
89 
90   if (gst_structure_has_name (s, "video/x-h265"))
91     return MPP_VIDEO_CodingHEVC;
92 
93   if (gst_structure_has_name (s, "video/x-av1"))
94     return MPP_VIDEO_CodingAV1;
95 
96   if (gst_structure_has_name (s, "video/mpeg")) {
97     gint mpegversion = 0;
98     if (gst_structure_get_int (s, "mpegversion", &mpegversion)) {
99       switch (mpegversion) {
100         case 1:
101         case 2:
102           return MPP_VIDEO_CodingMPEG2;
103         case 4:
104           return MPP_VIDEO_CodingMPEG4;
105         default:
106           g_assert_not_reached ();
107           return MPP_VIDEO_CodingUnused;
108       }
109     }
110   }
111 
112   if (gst_structure_has_name (s, "video/x-vp8"))
113     return MPP_VIDEO_CodingVP8;
114 
115   if (gst_structure_has_name (s, "video/x-vp9"))
116     return MPP_VIDEO_CodingVP9;
117 
118   return MPP_VIDEO_CodingUnused;
119 }
120 
121 static void
gst_mpp_video_dec_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)122 gst_mpp_video_dec_set_property (GObject * object,
123     guint prop_id, const GValue * value, GParamSpec * pspec)
124 {
125   GstVideoDecoder *decoder = GST_VIDEO_DECODER (object);
126   GstMppDec *mppdec = GST_MPP_DEC (decoder);
127 
128   switch (prop_id) {
129     case PROP_FORMAT:{
130       if (mppdec->input_state)
131         GST_WARNING_OBJECT (decoder, "unable to change output format");
132       else
133         mppdec->format = g_value_get_enum (value);
134       break;
135     }
136     case PROP_ARM_AFBC:{
137       if (mppdec->input_state)
138         GST_WARNING_OBJECT (decoder, "unable to change ARM AFBC");
139       else
140         mppdec->arm_afbc = g_value_get_boolean (value);
141       break;
142     }
143     default:
144       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
145       return;
146   }
147 }
148 
149 static void
gst_mpp_video_dec_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)150 gst_mpp_video_dec_get_property (GObject * object,
151     guint prop_id, GValue * value, GParamSpec * pspec)
152 {
153   GstVideoDecoder *decoder = GST_VIDEO_DECODER (object);
154   GstMppDec *mppdec = GST_MPP_DEC (decoder);
155 
156   switch (prop_id) {
157     case PROP_FORMAT:
158       g_value_set_enum (value, mppdec->format);
159       break;
160     case PROP_ARM_AFBC:
161       g_value_set_boolean (value, mppdec->arm_afbc);
162       break;
163     default:
164       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
165       break;
166   }
167 }
168 
169 static gboolean
gst_mpp_video_dec_set_format(GstVideoDecoder * decoder,GstVideoCodecState * state)170 gst_mpp_video_dec_set_format (GstVideoDecoder * decoder,
171     GstVideoCodecState * state)
172 {
173   GstVideoDecoderClass *pclass = GST_VIDEO_DECODER_CLASS (parent_class);
174   GstMppDec *mppdec = GST_MPP_DEC (decoder);
175   GstStructure *structure;
176   const gchar *chroma_format;
177 
178   structure = gst_caps_get_structure (state->caps, 0);
179   mppdec->mpp_type = gst_mpp_video_dec_get_mpp_type (structure);
180   g_return_val_if_fail (mppdec->mpp_type != MPP_VIDEO_CodingUnused, FALSE);
181 
182   /* MPP doesn't support YUV444 for h264 */
183   if (mppdec->mpp_type == MPP_VIDEO_CodingAVC) {
184     chroma_format = gst_structure_get_string (structure, "chroma-format");
185     if (g_strcmp0 (chroma_format, "4:4:4") == 0)
186       return FALSE;
187   }
188 
189   return pclass->set_format (decoder, state);
190 }
191 
192 static gboolean
gst_mpp_video_dec_startup(GstVideoDecoder * decoder)193 gst_mpp_video_dec_startup (GstVideoDecoder * decoder)
194 {
195   GstMppVideoDec *self = GST_MPP_VIDEO_DEC (decoder);
196   GstMppDec *mppdec = GST_MPP_DEC (decoder);
197   GstVideoCodecState *state = mppdec->input_state;
198   GstBuffer *codec_data = state->codec_data;
199   GstMapInfo mapinfo = { 0, };
200   MppPacket mpkt;
201 
202   /* Send extra codec data */
203   if (codec_data) {
204     gst_buffer_ref (codec_data);
205     gst_buffer_map (codec_data, &mapinfo, GST_MAP_READ);
206     mpp_packet_init (&mpkt, mapinfo.data, mapinfo.size);
207     mpp_packet_set_extra_data (mpkt);
208 
209     mppdec->mpi->decode_put_packet (mppdec->mpp_ctx, mpkt);
210 
211     mpp_packet_deinit (&mpkt);
212     gst_buffer_unmap (codec_data, &mapinfo);
213     gst_buffer_unref (codec_data);
214   }
215 
216   if (mppdec->arm_afbc) {
217     MppFrameFormat mpp_format = MPP_FMT_YUV420SP | MPP_FRAME_FBC_AFBC_V2;
218     mppdec->mpi->control (mppdec->mpp_ctx, MPP_DEC_SET_OUTPUT_FORMAT,
219         &mpp_format);
220   }
221 
222   self->poll_timeout = 0;
223 
224   return TRUE;
225 }
226 
227 static MppPacket
gst_mpp_video_dec_get_mpp_packet(GstVideoDecoder * decoder UNUSED,GstMapInfo * mapinfo)228 gst_mpp_video_dec_get_mpp_packet (GstVideoDecoder * decoder UNUSED,
229     GstMapInfo * mapinfo)
230 {
231   MppPacket mpkt = NULL;
232   mpp_packet_init (&mpkt, mapinfo->data, mapinfo->size);
233   return mpkt;
234 }
235 
236 static gboolean
gst_mpp_video_dec_send_mpp_packet(GstVideoDecoder * decoder,MppPacket mpkt,gint timeout_ms)237 gst_mpp_video_dec_send_mpp_packet (GstVideoDecoder * decoder,
238     MppPacket mpkt, gint timeout_ms)
239 {
240   GstMppDec *mppdec = GST_MPP_DEC (decoder);
241   gint interval_ms = 2;
242   MPP_RET ret;
243 
244   do {
245     ret = mppdec->mpi->decode_put_packet (mppdec->mpp_ctx, mpkt);
246     if (!ret) {
247       mpp_packet_deinit (&mpkt);
248       return TRUE;
249     }
250 
251     g_usleep (interval_ms * 1000);
252     timeout_ms -= interval_ms;
253   } while (timeout_ms > 0);
254 
255   return FALSE;
256 }
257 
258 static MppFrame
gst_mpp_video_dec_poll_mpp_frame(GstVideoDecoder * decoder,gint timeout_ms)259 gst_mpp_video_dec_poll_mpp_frame (GstVideoDecoder * decoder, gint timeout_ms)
260 {
261   GstMppVideoDec *self = GST_MPP_VIDEO_DEC (decoder);
262   GstMppDec *mppdec = GST_MPP_DEC (decoder);
263   MppFrame mframe = NULL;
264 
265   if (self->poll_timeout != timeout_ms) {
266     self->poll_timeout = timeout_ms;
267     mppdec->mpi->control (mppdec->mpp_ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout_ms);
268   }
269 
270   mppdec->mpi->decode_get_frame (mppdec->mpp_ctx, &mframe);
271 
272   return mframe;
273 }
274 
275 static gboolean
gst_mpp_video_dec_shutdown(GstVideoDecoder * decoder,gboolean drain)276 gst_mpp_video_dec_shutdown (GstVideoDecoder * decoder, gboolean drain)
277 {
278   GstMppDec *mppdec = GST_MPP_DEC (decoder);
279   MppPacket mpkt;
280   MPP_RET ret;
281 
282   /* It's safe to stop decoding immediately */
283   if (!drain) {
284     /* Interrupt the frame polling */
285     mppdec->mpi->reset (mppdec->mpp_ctx);
286     return FALSE;
287   }
288 
289   mpp_packet_init (&mpkt, NULL, 0);
290   mpp_packet_set_eos (mpkt);
291 
292   while (1) {
293     ret = mppdec->mpi->decode_put_packet (mppdec->mpp_ctx, mpkt);
294     if (!ret)
295       break;
296 
297     g_usleep (1000);
298   }
299 
300   mpp_packet_deinit (&mpkt);
301   return TRUE;
302 }
303 
304 #define GST_TYPE_MPP_VIDEO_DEC_FORMAT (gst_mpp_video_dec_format_get_type ())
305 static GType
gst_mpp_video_dec_format_get_type(void)306 gst_mpp_video_dec_format_get_type (void)
307 {
308   static GType format = 0;
309 
310   if (!format) {
311     static const GEnumValue formats[] = {
312       {GST_VIDEO_FORMAT_UNKNOWN, "Auto", "auto"},
313       {GST_VIDEO_FORMAT_NV12, "NV12", "NV12"},
314       {GST_VIDEO_FORMAT_NV21, "NV21", "NV21"},
315       {GST_VIDEO_FORMAT_I420, "I420", "I420"},
316       {GST_VIDEO_FORMAT_YV12, "YV12", "YV12"},
317       {GST_VIDEO_FORMAT_NV16, "NV16", "NV16"},
318       {GST_VIDEO_FORMAT_NV61, "NV61", "NV61"},
319       {GST_VIDEO_FORMAT_BGR16, "BGR565", "BGR16"},
320       {GST_VIDEO_FORMAT_RGB, "RGB", "RGB"},
321       {GST_VIDEO_FORMAT_BGR, "BGR", "BGR"},
322       {GST_VIDEO_FORMAT_RGBA, "RGBA8888", "RGBA"},
323       {GST_VIDEO_FORMAT_BGRA, "BGRA8888", "BGRA"},
324       {GST_VIDEO_FORMAT_RGBx, "RGBX8888", "RGBx"},
325       {GST_VIDEO_FORMAT_BGRx, "BGRX8888", "BGRx"},
326       {0, NULL, NULL}
327     };
328     format = g_enum_register_static ("GstMppVideoDecFormat", formats);
329   }
330   return format;
331 }
332 
333 static void
gst_mpp_video_dec_init(GstMppVideoDec * self)334 gst_mpp_video_dec_init (GstMppVideoDec * self)
335 {
336   GstMppDec *mppdec = GST_MPP_DEC (self);
337   mppdec->format = DEFAULT_PROP_FORMAT;
338   mppdec->arm_afbc = DEFAULT_PROP_ARM_AFBC;
339 }
340 
341 static void
gst_mpp_video_dec_setup_default_format(void)342 gst_mpp_video_dec_setup_default_format (void)
343 {
344   GEnumClass *class;
345   GEnumValue *value;
346   const gchar *env;
347 
348   env = g_getenv ("GST_MPP_VIDEODEC_DEFAULT_FORMAT");
349   if (!env)
350     return;
351 
352   class = g_type_class_ref (GST_TYPE_MPP_VIDEO_DEC_FORMAT);
353 
354   value = g_enum_get_value_by_nick (class, env);
355   if (value)
356     DEFAULT_PROP_FORMAT = value->value;
357 
358   g_type_class_unref (class);
359 }
360 
361 static void
gst_mpp_video_dec_class_init(GstMppVideoDecClass * klass)362 gst_mpp_video_dec_class_init (GstMppVideoDecClass * klass)
363 {
364   GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
365   GstMppDecClass *pclass = GST_MPP_DEC_CLASS (klass);
366   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
367   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
368 
369   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "mppvideodec", 0,
370       "MPP video decoder");
371 
372   decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_mpp_video_dec_set_format);
373 
374   pclass->startup = GST_DEBUG_FUNCPTR (gst_mpp_video_dec_startup);
375   pclass->get_mpp_packet = GST_DEBUG_FUNCPTR (gst_mpp_video_dec_get_mpp_packet);
376   pclass->send_mpp_packet =
377       GST_DEBUG_FUNCPTR (gst_mpp_video_dec_send_mpp_packet);
378   pclass->poll_mpp_frame = GST_DEBUG_FUNCPTR (gst_mpp_video_dec_poll_mpp_frame);
379   pclass->shutdown = GST_DEBUG_FUNCPTR (gst_mpp_video_dec_shutdown);
380 
381   gobject_class->set_property =
382       GST_DEBUG_FUNCPTR (gst_mpp_video_dec_set_property);
383   gobject_class->get_property =
384       GST_DEBUG_FUNCPTR (gst_mpp_video_dec_get_property);
385 
386   gst_mpp_video_dec_setup_default_format ();
387 
388 #ifdef HAVE_RGA
389   g_object_class_install_property (gobject_class, PROP_FORMAT,
390       g_param_spec_enum ("format", "Prefered output format",
391           "Prefered output format",
392           GST_TYPE_MPP_VIDEO_DEC_FORMAT, DEFAULT_PROP_FORMAT,
393           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
394 #endif
395 
396   if (g_getenv ("GST_MPP_VIDEODEC_DEFAULT_ARM_AFBC"))
397     DEFAULT_PROP_ARM_AFBC = TRUE;
398 
399   g_object_class_install_property (gobject_class, PROP_ARM_AFBC,
400       g_param_spec_boolean ("arm-afbc", "ARM AFBC",
401           "Prefer ARM AFBC compressed format", DEFAULT_PROP_ARM_AFBC,
402           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
403 
404   gst_element_class_add_pad_template (element_class,
405       gst_static_pad_template_get (&gst_mpp_video_dec_src_template));
406 
407   gst_element_class_add_pad_template (element_class,
408       gst_static_pad_template_get (&gst_mpp_video_dec_sink_template));
409 
410   gst_element_class_set_static_metadata (element_class,
411       "Rockchip's MPP video decoder", "Decoder/Video",
412       "Multicodec (HEVC / AVC / VP8 / VP9) hardware decoder",
413       "Randy Li <randy.li@rock-chips.com>, "
414       "Jeffy Chen <jeffy.chen@rock-chips.com>");
415 }
416 
417 gboolean
gst_mpp_video_dec_register(GstPlugin * plugin,guint rank)418 gst_mpp_video_dec_register (GstPlugin * plugin, guint rank)
419 {
420   return gst_element_register (plugin, "mppvideodec", rank,
421       gst_mpp_video_dec_get_type ());
422 }
423