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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5555>
This commit is contained in:
Nicolas Dufresne 2023-10-24 17:04:17 -04:00 committed by GStreamer Marge Bot
parent 7edb6a5634
commit 18f3ea41c0
9 changed files with 111 additions and 23 deletions

View File

@ -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);
}

View File

@ -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");

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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);