v4l2object: Add interlace-mode back to caps for camera

skip_try_fmt_probes is set to TRUE for v4l2src to skip interlace-mode and
colorimetry when probe caps. gst_v4l2_object_set_format_full() will add
colorimetry back to caps when iterating over the negotiated caps. There is
one case that v4l2src is first in preview state then starts recording.
v4l2src caps will change with an additional interlace-mode structure after
renegotiation, then v4l2src needs to reset. But this camera driver can't
orphan buffer pool, it causes require buffer failed as streaming is still
in active state.

To fix this, also need to add interlace-mode back to caps for camera to
avoid reset.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/961>
This commit is contained in:
Hou Qi 2021-04-22 15:01:32 +08:00 committed by Nicolas Dufresne
parent 5fa3325335
commit 5e932395a4

View file

@ -2007,7 +2007,7 @@ gst_v4l2_object_get_interlace_mode (enum v4l2_field field,
case V4L2_FIELD_ANY: case V4L2_FIELD_ANY:
GST_ERROR GST_ERROR
("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n"); ("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n");
/* fallthrough */ return FALSE;
case V4L2_FIELD_NONE: case V4L2_FIELD_NONE:
*interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; *interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
return TRUE; return TRUE;
@ -3477,6 +3477,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
enum v4l2_ycbcr_encoding matrix = 0; enum v4l2_ycbcr_encoding matrix = 0;
enum v4l2_xfer_func transfer = 0; enum v4l2_xfer_func transfer = 0;
GstStructure *s; GstStructure *s;
gboolean disable_interlacing = FALSE;
gboolean disable_colorimetry = FALSE; gboolean disable_colorimetry = FALSE;
g_return_val_if_fail (!v4l2object->skip_try_fmt_probes || g_return_val_if_fail (!v4l2object->skip_try_fmt_probes ||
@ -3804,12 +3805,18 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
/* used to check colorimetry and interlace mode fields presence */ /* used to check colorimetry and interlace mode fields presence */
s = gst_caps_get_structure (caps, 0); s = gst_caps_get_structure (caps, 0);
if (!gst_v4l2_object_get_interlace_mode (format.fmt.pix.field, if (gst_v4l2_object_get_interlace_mode (format.fmt.pix.field,
&info.interlace_mode)) &info.interlace_mode)) {
goto invalid_field; if (gst_structure_has_field (s, "interlace-mode")) {
if (gst_structure_has_field (s, "interlace-mode")) { if (format.fmt.pix.field != field)
if (format.fmt.pix.field != field) goto invalid_field;
goto invalid_field; }
} else {
/* The driver (or libv4l2) is miss-behaving, just ignore interlace-mode from
* the TRY_FMT */
disable_interlacing = TRUE;
if (gst_structure_has_field (s, "interlace-mode"))
gst_structure_remove_field (s, "interlace-mode");
} }
if (gst_v4l2_object_get_colorspace (v4l2object, &format, &info.colorimetry)) { if (gst_v4l2_object_get_colorspace (v4l2object, &format, &info.colorimetry)) {
@ -3826,8 +3833,12 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
} }
/* In case we have skipped the try_fmt probes, we'll need to set the /* In case we have skipped the try_fmt probes, we'll need to set the
* colorimetry back into the caps. */ * interlace-mode and colorimetry back into the caps. */
if (v4l2object->skip_try_fmt_probes) { if (v4l2object->skip_try_fmt_probes) {
if (!disable_interlacing && !gst_structure_has_field (s, "interlace-mode")) {
gst_structure_set (s, "interlace-mode", G_TYPE_STRING,
gst_video_interlace_mode_to_string (info.interlace_mode), NULL);
}
if (!disable_colorimetry && !gst_structure_has_field (s, "colorimetry")) { if (!disable_colorimetry && !gst_structure_has_field (s, "colorimetry")) {
gchar *str = gst_video_colorimetry_to_string (&info.colorimetry); gchar *str = gst_video_colorimetry_to_string (&info.colorimetry);
gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL); gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL);