+
+/**
+ * gst_v4l2_object_get_buffer_pool:
+ * @src: a #GstV4l2Object
+ *
+ * Returns: (nullable) (transfer full): the instance of the #GstBufferPool used
+ * by the v4l2object; unref it after usage.
+ */
+GstBufferPool *
+gst_v4l2_object_get_buffer_pool (GstV4l2Object * v4l2object)
+{
+ GstBufferPool *ret = NULL;
+
+ g_return_val_if_fail (v4l2object != NULL, NULL);
+
+ GST_OBJECT_LOCK (v4l2object->element);
+ if (v4l2object->pool)
+ ret = gst_object_ref (v4l2object->pool);
+ GST_OBJECT_UNLOCK (v4l2object->element);
+
+ return ret;
+}
+
+/**
+ * gst_v4l2_object_poll:
+ * @v4l2object: a #GstV4l2Object
+ * @timeout: timeout of type #GstClockTime
+ *
+ * Poll the video file descriptor for read when this is a capture, write when
+ * this is an output. It will also watch for errors and source change events.
+ * If a source change event is received, %GST_V4L2_FLOW_RESOLUTION_CHANGE will
+ * be returned. If the poll was interrupted, %GST_FLOW_FLUSHING is returned.
+ * If there was no read or write indicator, %GST_V4L2_FLOW_LAST_BUFFER is
+ * returned. It may also return %GST_FLOW_ERROR if some unexpected error
+ * occured.
+ *
+ * Returns: GST_FLOW_OK if buffers are ready to be queued or dequeued.
+ */
+GstFlowReturn
+gst_v4l2_object_poll (GstV4l2Object * v4l2object, GstClockTime timeout)
+{
+ gint ret;
+
+ if (!v4l2object->can_poll_device) {
+ if (timeout != 0)
+ goto done;
+ else
+ goto no_buffers;
+ }
+
+ GST_LOG_OBJECT (v4l2object->dbg_obj, "polling device");
+
+again:
+ ret = gst_poll_wait (v4l2object->poll, timeout);
+ if (G_UNLIKELY (ret < 0)) {
+ switch (errno) {
+ case EBUSY:
+ goto stopped;
+ case EAGAIN:
+ case EINTR:
+ goto again;
+ case ENXIO:
+ GST_WARNING_OBJECT (v4l2object->dbg_obj,
+ "v4l2 device doesn't support polling. Disabling"
+ " using libv4l2 in this case may cause deadlocks");
+ v4l2object->can_poll_device = FALSE;
+ goto done;
+ default:
+ goto select_error;
+ }
+ }
+
+ if (gst_poll_fd_has_error (v4l2object->poll, &v4l2object->pollfd))
+ goto select_error;
+
+ /* PRI is used to signal that events are available */
+ if (gst_poll_fd_has_pri (v4l2object->poll, &v4l2object->pollfd)) {
+ struct v4l2_event event = { 0, };
+
+ if (!gst_v4l2_dequeue_event (v4l2object, &event))
+ goto dqevent_failed;
+
+ if (event.type != V4L2_EVENT_SOURCE_CHANGE) {
+ GST_INFO_OBJECT (v4l2object->dbg_obj,
+ "Received unhandled event, ignoring.");
+ goto again;
+ }
+
+ if ((event.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION) == 0) {
+ GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+ "Received non-resolution source-change, ignoring.");
+ goto again;
+ }
+
+ if (v4l2object->formats)
+ gst_v4l2_object_clear_format_list (v4l2object);
+
+ return GST_V4L2_FLOW_RESOLUTION_CHANGE;
+ }
+
+ if (ret == 0)
+ goto no_buffers;
+
+done:
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+stopped:
+ {
+ GST_DEBUG_OBJECT (v4l2object->dbg_obj, "stop called");
+ return GST_FLOW_FLUSHING;
+ }
+select_error:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
+ ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
+ return GST_FLOW_ERROR;
+ }
+no_buffers:
+ {
+ return GST_V4L2_FLOW_LAST_BUFFER;
+ }
+dqevent_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
+ ("dqevent error: %s (%d)", g_strerror (errno), errno));
+ return GST_FLOW_ERROR;
+ }
+}
+
+/**
+ * gst_v4l2_object_subscribe_event:
+ * @v4l2object: a #GstV4l2Object
+ * @event: the event ID
+ *
+ * Subscribe to an event, and enable polling for these. Note that only
+ * %V4L2_EVENT_SOURCE_CHANGE is currently supported by the poll helper.
+ *
+ * Returns: %TRUE if the driver supports this event
+ */
+gboolean
+gst_v4l2_object_subscribe_event (GstV4l2Object * v4l2object, guint32 event)
+{
+ guint32 id = 0;
+
+ g_return_val_if_fail (v4l2object != NULL, FALSE);
+ g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE);
+
+ v4l2object->get_in_out_func (v4l2object, &id);
+
+ if (gst_v4l2_subscribe_event (v4l2object, event, id)) {
+ gst_poll_fd_ctl_pri (v4l2object->poll, &v4l2object->pollfd, TRUE);
+ return TRUE;
+ }
+
+ return FALSE;
+}