v4l2: encoder: Add dynamic framerate support

This is not trully supported in V4L2, but we can emulate this similar to
what other elements do. In this patch we ensure that 0/1 is supported by
encoders (caps query),and uses a default of 30fps whenever we need to
set a framerate into the driver.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7352>
This commit is contained in:
Nicolas Dufresne 2024-08-13 16:38:37 -04:00
parent 5182cac9be
commit ee925c506c
2 changed files with 38 additions and 9 deletions

View file

@ -4380,15 +4380,25 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
goto done; goto done;
} }
/* Note: V4L2 wants the frame interval, we have the frame rate */ /* Variable framerate is not a V4L2 concept, simply default to 30fps */
streamparm.parm.capture.timeperframe.numerator = fps_d; if (fps_n == 0 && fps_d == 1) {
streamparm.parm.capture.timeperframe.denominator = fps_n; GST_DEBUG_OBJECT (v4l2object->dbg_obj,
"Variable framerate not supported, assuming 30fps");
streamparm.parm.capture.timeperframe.numerator = 1;
streamparm.parm.capture.timeperframe.denominator = 30;
} else {
/* Note: V4L2 wants the frame interval, we have the frame rate */
streamparm.parm.capture.timeperframe.numerator = fps_d;
streamparm.parm.capture.timeperframe.denominator = fps_n;
}
/* some cheap USB cam's won't accept any change */ /* some cheap USB cam's won't accept any change */
if (v4l2object->ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0) if (v4l2object->ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
goto set_parm_failed; goto set_parm_failed;
if (streamparm.parm.capture.timeperframe.numerator > 0 && if (fps_n == 0 && fps_d == 1) {
/* just keep reporting variable framerate */
} else if (streamparm.parm.capture.timeperframe.numerator > 0 &&
streamparm.parm.capture.timeperframe.denominator > 0) { streamparm.parm.capture.timeperframe.denominator > 0) {
/* get new values */ /* get new values */
fps_d = streamparm.parm.capture.timeperframe.numerator; fps_d = streamparm.parm.capture.timeperframe.numerator;
@ -4423,14 +4433,24 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
goto done; goto done;
} }
/* Note: V4L2 wants the frame interval, we have the frame rate */ /* Variable framerate is not a V4L2 concept, simply default to 30fps */
streamparm.parm.output.timeperframe.numerator = fps_d; if (fps_n == 0 && fps_d == 1) {
streamparm.parm.output.timeperframe.denominator = fps_n; GST_DEBUG_OBJECT (v4l2object->dbg_obj,
"Variable framerate not supported, assuming 30fps");
streamparm.parm.output.timeperframe.numerator = 1;
streamparm.parm.output.timeperframe.denominator = 30;
} else {
/* Note: V4L2 wants the frame interval, we have the frame rate */
streamparm.parm.output.timeperframe.numerator = fps_d;
streamparm.parm.output.timeperframe.denominator = fps_n;
}
if (v4l2object->ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0) if (v4l2object->ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
goto set_parm_failed; goto set_parm_failed;
if (streamparm.parm.output.timeperframe.numerator > 0 && if (fps_n == 0 && fps_d == 1) {
/* just keep reporting variable framerate */
} else if (streamparm.parm.output.timeperframe.numerator > 0 &&
streamparm.parm.output.timeperframe.denominator > 0) { streamparm.parm.output.timeperframe.denominator > 0) {
/* get new values */ /* get new values */
fps_d = streamparm.parm.output.timeperframe.numerator; fps_d = streamparm.parm.output.timeperframe.numerator;

View file

@ -111,7 +111,7 @@ gst_v4l2_video_enc_open (GstVideoEncoder * encoder)
{ {
GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder); GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
GstV4l2Error error = GST_V4L2_ERROR_INIT; GstV4l2Error error = GST_V4L2_ERROR_INIT;
GstCaps *codec_caps; GstCaps *tmp_caps, *codec_caps;
GST_DEBUG_OBJECT (self, "Opening"); GST_DEBUG_OBJECT (self, "Opening");
@ -124,6 +124,15 @@ gst_v4l2_video_enc_open (GstVideoEncoder * encoder)
self->probed_sinkcaps = gst_v4l2_object_probe_caps (self->v4l2output, self->probed_sinkcaps = gst_v4l2_object_probe_caps (self->v4l2output,
gst_v4l2_object_get_raw_caps ()); gst_v4l2_object_get_raw_caps ());
/*
* Relax the framerate to always allow 0/1 regardless of what the driver
* wants. This improve compatibility of the encoder with sources which may
* not know the frame rate
*/
tmp_caps = gst_caps_copy (self->probed_sinkcaps);
gst_caps_set_simple (tmp_caps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
gst_caps_append (self->probed_sinkcaps, tmp_caps);
if (gst_caps_is_empty (self->probed_sinkcaps)) if (gst_caps_is_empty (self->probed_sinkcaps))
goto no_raw_format; goto no_raw_format;