From 18f3ea41c02d125366d4b9205961285e68fe58ff Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 24 Oct 2023 17:04:17 -0400 Subject: [PATCH] v4l2codecs: Add a doc generation mode This is enabled through an env, it allow exposing all elements without the needed driver supports. This is useful to fill the documentation cache. Part-of: --- .../sys/v4l2codecs/gstv4l2codecav1dec.c | 12 ++++-- .../sys/v4l2codecs/gstv4l2codecdevice.c | 8 ++++ .../sys/v4l2codecs/gstv4l2codech264dec.c | 11 +++++- .../sys/v4l2codecs/gstv4l2codech265dec.c | 11 +++++- .../sys/v4l2codecs/gstv4l2codecmpeg2dec.c | 11 +++++- .../sys/v4l2codecs/gstv4l2codecvp8dec.c | 14 +++++-- .../sys/v4l2codecs/gstv4l2codecvp9dec.c | 14 +++++-- .../sys/v4l2codecs/gstv4l2decoder.c | 37 ++++++++++++++++++- .../sys/v4l2codecs/gstv4l2decoder.h | 16 ++++---- 9 files changed, 111 insertions(+), 23 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c index 5478768b65..ebf289ba5c 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c @@ -1600,11 +1600,16 @@ void gst_v4l2_codec_av1_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, GstV4l2CodecDevice * device, guint rank) { - GstCaps *src_caps; + GstCaps *src_caps = NULL; GST_DEBUG_CATEGORY_INIT (v4l2_av1dec_debug, "v4l2codecs-av1dec", 0, "V4L2 stateless AV1 decoder"); + if (gst_v4l2_decoder_in_doc_mode (decoder)) { + device->src_caps = gst_static_caps_get (&static_src_caps); + goto register_element; + } + if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_AV1_FRAME, 320, 240, 8)) return; @@ -1635,7 +1640,7 @@ gst_v4l2_codec_av1_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, GST_WARNING ("Not registering AV1 decoder as it failed ABI check."); goto done; } - +register_element: gst_v4l2_decoder_register (plugin, GST_TYPE_V4L2_CODEC_AV1_DEC, (GClassInitFunc) gst_v4l2_codec_av1_dec_subclass_init, gst_mini_object_ref (GST_MINI_OBJECT (device)), @@ -1643,5 +1648,6 @@ gst_v4l2_codec_av1_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, "v4l2sl%sav1dec", device, rank, NULL); done: - gst_caps_unref (src_caps); + if (src_caps) + gst_caps_unref (src_caps); } diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecdevice.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecdevice.c index 0497a1a018..9be940e80c 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecdevice.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecdevice.c @@ -313,6 +313,14 @@ gst_v4l2_codec_find_devices (void) GList *udev_devices, *d; GQueue devices = G_QUEUE_INIT; + /* Provide a fake device in documentation generation mode */ + if (!g_strcmp0 (g_getenv ("GST_V4L2_CODEC_GEN_DOC"), "1")) { + GST_INFO ("Simulating V4L2 CODECS for doc generator."); + g_queue_push_tail (&devices, gst_v4l2_codec_device_new ("docdec-proc", + MEDIA_ENT_F_PROC_VIDEO_DECODER, "/dev/mediaX", "/dev/videoX")); + return devices.head; + } + client = g_udev_client_new (NULL); udev_devices = g_udev_client_query_by_subsystem (client, "media"); diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c index 4ae2dcdc7d..666dd5e5ec 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c @@ -1593,12 +1593,17 @@ void gst_v4l2_codec_h264_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, GstV4l2CodecDevice * device, guint rank) { - GstCaps *src_caps; + GstCaps *src_caps = NULL; guint version; GST_DEBUG_CATEGORY_INIT (v4l2_h264dec_debug, "v4l2codecs-h264dec", 0, "V4L2 stateless h264 decoder"); + if (gst_v4l2_decoder_in_doc_mode (decoder)) { + device->src_caps = gst_static_caps_get (&static_src_caps); + goto register_element; + } + if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_H264_SLICE, 320, 240, 8)) return; @@ -1627,6 +1632,7 @@ gst_v4l2_codec_h264_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, goto done; } +register_element: gst_v4l2_decoder_register (plugin, GST_TYPE_V4L2_CODEC_H264_DEC, (GClassInitFunc) gst_v4l2_codec_h264_dec_subclass_init, @@ -1635,5 +1641,6 @@ gst_v4l2_codec_h264_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, "v4l2sl%sh264dec", device, rank, NULL); done: - gst_caps_unref (src_caps); + if (src_caps) + gst_caps_unref (src_caps); } diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c index bef7a55b86..cabd68e204 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c @@ -1724,12 +1724,17 @@ void gst_v4l2_codec_h265_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, GstV4l2CodecDevice * device, guint rank) { - GstCaps *src_caps; + GstCaps *src_caps = NULL; guint version; GST_DEBUG_CATEGORY_INIT (v4l2_h265dec_debug, "v4l2codecs-h265dec", 0, "V4L2 stateless h265 decoder"); + if (gst_v4l2_decoder_in_doc_mode (decoder)) { + device->src_caps = gst_static_caps_get (&static_src_caps); + goto register_element; + } + if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_HEVC_SLICE, 320, 240, 8)) return; @@ -1758,6 +1763,7 @@ gst_v4l2_codec_h265_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, goto done; } +register_element: gst_v4l2_decoder_register (plugin, GST_TYPE_V4L2_CODEC_H265_DEC, (GClassInitFunc) gst_v4l2_codec_h265_dec_subclass_init, gst_mini_object_ref (GST_MINI_OBJECT (device)), @@ -1765,5 +1771,6 @@ gst_v4l2_codec_h265_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, "v4l2sl%sh265dec", device, rank, NULL); done: - gst_caps_unref (src_caps); + if (src_caps) + gst_caps_unref (src_caps); } diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c index 6725162b36..eb320d9d55 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c @@ -1111,11 +1111,16 @@ void gst_v4l2_codec_mpeg2_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, GstV4l2CodecDevice * device, guint rank) { - GstCaps *src_caps; + GstCaps *src_caps = NULL; GST_DEBUG_CATEGORY_INIT (v4l2_mpeg2dec_debug, "v4l2codecs-mpeg2dec", 0, "V4L2 stateless mpeg2 decoder"); + if (gst_v4l2_decoder_in_doc_mode (decoder)) { + device->src_caps = gst_static_caps_get (&static_src_caps); + goto register_element; + } + if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_MPEG2_SLICE, 320, 240, 8)) return; @@ -1133,6 +1138,7 @@ gst_v4l2_codec_mpeg2_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, device->src_caps = gst_v4l2_decoder_enum_all_src_formats (decoder, &static_src_caps); +register_element: gst_v4l2_decoder_register (plugin, GST_TYPE_V4L2_CODEC_MPEG2_DEC, (GClassInitFunc) gst_v4l2_codec_mpeg2_dec_subclass_init, gst_mini_object_ref (GST_MINI_OBJECT (device)), @@ -1140,5 +1146,6 @@ gst_v4l2_codec_mpeg2_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, "v4l2sl%smpeg2dec", device, rank, NULL); done: - gst_caps_unref (src_caps); + if (src_caps) + gst_caps_unref (src_caps); } diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c index 45536ca250..86429032f8 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c @@ -987,11 +987,16 @@ gst_v4l2_codec_vp8_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, GstV4l2CodecDevice * device, guint rank) { gchar *element_name; - GstCaps *src_caps, *alpha_caps; + GstCaps *src_caps = NULL, *alpha_caps; GST_DEBUG_CATEGORY_INIT (v4l2_vp8dec_debug, "v4l2codecs-vp8dec", 0, "V4L2 stateless VP8 decoder"); + if (gst_v4l2_decoder_in_doc_mode (decoder)) { + device->src_caps = gst_static_caps_get (&static_src_caps); + goto register_element; + } + if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_VP8_FRAME, 320, 240, 8)) return; @@ -1009,6 +1014,7 @@ gst_v4l2_codec_vp8_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, device->src_caps = gst_v4l2_decoder_enum_all_src_formats (decoder, &static_src_caps); +register_element: gst_v4l2_decoder_register (plugin, GST_TYPE_V4L2_CODEC_VP8_DEC, (GClassInitFunc) gst_v4l2_codec_vp8_dec_subclass_init, gst_mini_object_ref (GST_MINI_OBJECT (device)), @@ -1020,7 +1026,8 @@ gst_v4l2_codec_vp8_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, alpha_caps = gst_caps_from_string ("video/x-raw,format={I420, NV12}"); - if (gst_caps_can_intersect (device->src_caps, alpha_caps)) + if (gst_v4l2_decoder_in_doc_mode (decoder) || + gst_caps_can_intersect (device->src_caps, alpha_caps)) gst_v4l2_codec_alpha_decode_bin_register (plugin, (GClassInitFunc) gst_v4l2_codec_vp8_alpha_decode_bin_subclass_init, element_name, "v4l2slvp8%salphadecodebin", device, rank); @@ -1028,5 +1035,6 @@ gst_v4l2_codec_vp8_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, gst_caps_unref (alpha_caps); done: - gst_caps_unref (src_caps); + if (src_caps) + gst_caps_unref (src_caps); } diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c index b2ab0cb7e5..dc00cd75ef 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c @@ -1268,11 +1268,16 @@ gst_v4l2_codec_vp9_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, GstV4l2CodecDevice * device, guint rank) { gchar *element_name; - GstCaps *src_caps, *alpha_caps; + GstCaps *src_caps = NULL, *alpha_caps; GST_DEBUG_CATEGORY_INIT (v4l2_vp9dec_debug, "v4l2codecs-vp9dec", 0, "V4L2 stateless VP9 decoder"); + if (gst_v4l2_decoder_in_doc_mode (decoder)) { + device->src_caps = gst_static_caps_get (&static_src_caps); + goto register_element; + } + if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_VP9_FRAME, 320, 240, 8)) return; @@ -1290,6 +1295,7 @@ gst_v4l2_codec_vp9_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, device->src_caps = gst_v4l2_decoder_enum_all_src_formats (decoder, &static_src_caps); +register_element: gst_v4l2_decoder_register (plugin, GST_TYPE_V4L2_CODEC_VP9_DEC, (GClassInitFunc) gst_v4l2_codec_vp9_dec_subclass_init, gst_mini_object_ref (GST_MINI_OBJECT (device)), @@ -1301,7 +1307,8 @@ gst_v4l2_codec_vp9_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, alpha_caps = gst_caps_from_string ("video/x-raw,format={I420, NV12}"); - if (gst_caps_can_intersect (device->src_caps, alpha_caps)) + if (gst_v4l2_decoder_in_doc_mode (decoder) || + gst_caps_can_intersect (device->src_caps, alpha_caps)) gst_v4l2_codec_alpha_decode_bin_register (plugin, (GClassInitFunc) gst_v4l2_codec_vp9_alpha_decode_bin_subclass_init, element_name, "v4l2slvp9%salphadecodebin", device, rank); @@ -1309,5 +1316,6 @@ gst_v4l2_codec_vp9_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, gst_caps_unref (alpha_caps); done: - gst_caps_unref (src_caps); + if (src_caps) + gst_caps_unref (src_caps); } diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c index cf37148b3a..e4c40aa4c0 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c @@ -98,6 +98,9 @@ struct _GstV4l2Decoder /* detected features */ gboolean supports_holding_capture; gboolean supports_remove_buffers; + + /* special state for doc generator */ + gboolean doc_mode; }; G_DEFINE_TYPE_WITH_CODE (GstV4l2Decoder, gst_v4l2_decoder, GST_TYPE_OBJECT, @@ -141,7 +144,6 @@ static void gst_v4l2_decoder_class_init (GstV4l2DecoderClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = gst_v4l2_decoder_finalize; gobject_class->get_property = gst_v4l2_decoder_get_property; gobject_class->set_property = gst_v4l2_decoder_set_property; @@ -161,6 +163,9 @@ gst_v4l2_decoder_new (GstV4l2CodecDevice * device) "media-device", device->media_device_path, "video-device", device->video_device_path, NULL); + if (!g_strcmp0 (device->name, "docdec-proc")) + decoder->doc_mode = TRUE; + return gst_object_ref_sink (decoder); } @@ -182,6 +187,11 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self) guint32 capabilities; + if (self->doc_mode) { + self->opened = TRUE; + return TRUE; + } + self->media_fd = open (self->media_device, 0); if (self->media_fd < 0) { GST_ERROR_OBJECT (self, "Failed to open '%s': %s", @@ -329,6 +339,19 @@ gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self, gint i, g_return_val_if_fail (self->opened, FALSE); + if (self->doc_mode) { + guint32 all_fmt[] = { + V4L2_PIX_FMT_H264_SLICE, V4L2_PIX_FMT_HEVC_SLICE, V4L2_PIX_FMT_VP8_FRAME, + V4L2_PIX_FMT_MPEG2_SLICE, V4L2_PIX_FMT_VP9_FRAME, V4L2_PIX_FMT_AV1_FRAME, + }; + + if (i >= G_N_ELEMENTS (all_fmt)) + return FALSE; + + *out_fmt = all_fmt[i]; + return TRUE; + } + ret = ioctl (self->video_fd, VIDIOC_ENUM_FMT, &fmtdesc); if (ret < 0) { if (errno != EINVAL) @@ -1343,6 +1366,18 @@ gst_v4l2_decoder_has_remove_bufs (GstV4l2Decoder * self) return self->supports_remove_buffers; } +/** + * gst_v4l2_decoder_in_doc_mode: + * @slef: a #GstV4l2Decoder pointer + * + * Returns: %TRUE if running in documenetation genetator mode + */ +gboolean +gst_v4l2_decoder_in_doc_mode (GstV4l2Decoder * self) +{ + return self->doc_mode; +} + GstV4l2Request * gst_v4l2_request_ref (GstV4l2Request * request) { diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h index c744c31191..99271e3cb0 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h @@ -34,8 +34,8 @@ * * Since: 1.24 */ -#define GST_CODEC_PICTURE_TS_NS(picture) \ - gst_util_uint64_scale_int (GST_CODEC_PICTURE_FRAME_NUMBER(picture), 1000, 1) +#define GST_CODEC_PICTURE_TS_NS(picture) \ + gst_util_uint64_scale_int (GST_CODEC_PICTURE_FRAME_NUMBER(picture), 1000, 1) G_BEGIN_DECLS @@ -89,12 +89,12 @@ gint gst_v4l2_decoder_request_buffers (GstV4l2Decoder * self, gint gst_v4l2_decoder_create_buffers (GstV4l2Decoder * self, GstPadDirection direction, - guint num_buffers); + guint num_buffers); gint gst_v4l2_decoder_remove_buffers (GstV4l2Decoder * self, - GstPadDirection direction, + GstPadDirection direction, guint index, - guint num_buffers); + guint num_buffers); gboolean gst_v4l2_decoder_export_buffer (GstV4l2Decoder * self, GstPadDirection directon, @@ -115,7 +115,7 @@ gboolean gst_v4l2_decoder_get_controls (GstV4l2Decoder * self, gboolean gst_v4l2_decoder_query_control_size (GstV4l2Decoder * self, unsigned int control_id, - unsigned int *control_size); + unsigned int *control_size); void gst_v4l2_decoder_install_properties (GObjectClass * gobject_class, gint prop_offset, @@ -151,7 +151,9 @@ void gst_v4l2_decoder_set_render_delay (GstV4l2Decoder * self, guint gst_v4l2_decoder_get_render_delay (GstV4l2Decoder * self); -gboolean gst_v4l2_decoder_has_remove_bufs (GstV4l2Decoder * self); +gboolean gst_v4l2_decoder_has_remove_bufs (GstV4l2Decoder * self); + +gboolean gst_v4l2_decoder_in_doc_mode (GstV4l2Decoder * self); GstV4l2Request * gst_v4l2_request_ref (GstV4l2Request * request);