v4l2videodec: Add resolution change support
Support resolution change event.
https://bugzilla.gnome.org/show_bug.cgi?id=752962
UpStream Status: Pending
diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c
index 5a92dbb..2653331 100644
--- a/sys/v4l2/gstv4l2bufferpool.c
+++ b/sys/v4l2/gstv4l2bufferpool.c
@@ -1120,6 +1120,37 @@
}
static GstFlowReturn
+gst_v4l2_buffer_pool_dqevent (GstV4l2BufferPool * pool)
+{
+ GstV4l2Object *obj = pool->obj;
+ struct v4l2_event evt;
+
+ memset (&evt, 0x00, sizeof (struct v4l2_event));
+ if (obj->ioctl (pool->video_fd, VIDIOC_DQEVENT, &evt) < 0)
+ goto dqevent_failed;
+
+ switch (evt.type)
+ {
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return GST_V4L2_FLOW_SOURCE_CHANGE;
+ break;
+ case V4L2_EVENT_EOS:
+ return GST_V4L2_FLOW_LAST_BUFFER;
+ break;
+ default:
+ break;
+ }
+
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+dqevent_failed:
+ {
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstFlowReturn
gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
{
GstFlowReturn res;
@@ -1131,11 +1162,6 @@
gsize size;
gint i;
- if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
- goto poll_failed;
-
- GST_LOG_OBJECT (pool, "dequeueing a buffer");
-
res = gst_v4l2_allocator_dqbuf (pool->vallocator, &group);
if (res == GST_FLOW_EOS)
goto eos;
@@ -1263,11 +1289,6 @@
return GST_FLOW_OK;
/* ERRORS */
-poll_failed:
- {
- GST_DEBUG_OBJECT (pool, "poll error %s", gst_flow_get_name (res));
- return res;
- }
eos:
{
return GST_FLOW_EOS;
@@ -1285,6 +1306,30 @@
}
static GstFlowReturn
+gst_v4l2_buffer_pool_dequeue (GstV4l2BufferPool * pool, GstBuffer ** buffer)
+{
+ GstFlowReturn res;
+ GstV4l2Object *obj = pool->obj;
+
+ if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
+ goto poll_failed;
+
+ if (obj->can_wait_event && gst_poll_fd_can_read_pri (pool->poll, &pool->pollfd)) {
+ return gst_v4l2_buffer_pool_dqevent (pool);
+ }
+
+ GST_LOG_OBJECT (pool, "dequeueing a buffer");
+ return gst_v4l2_buffer_pool_dqbuf (pool, buffer);
+
+ /* ERRORS */
+poll_failed:
+ {
+ GST_DEBUG_OBJECT (pool, "poll error %s", gst_flow_get_name (res));
+ return res;
+ }
+}
+
+static GstFlowReturn
gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
GstBufferPoolAcquireParams * params)
{
@@ -1320,7 +1365,7 @@
/* just dequeue a buffer, we basically use the queue of v4l2 as the
* storage for our buffers. This function does poll first so we can
* interrupt it fine. */
- ret = gst_v4l2_buffer_pool_dqbuf (pool, buffer);
+ ret = gst_v4l2_buffer_pool_dequeue (pool, buffer);
break;
}
default:
@@ -1767,7 +1812,7 @@
}
/* buffer not from our pool, grab a frame and copy it into the target */
- if ((ret = gst_v4l2_buffer_pool_dqbuf (pool, &tmp)) != GST_FLOW_OK)
+ if ((ret = gst_v4l2_buffer_pool_dequeue (pool, &tmp)) != GST_FLOW_OK)
goto done;
/* An empty buffer on capture indicates the end of stream */
@@ -1920,7 +1965,7 @@
GstBuffer *out;
/* all buffers are queued, try to dequeue one and release it back
* into the pool so that _acquire can get to it again. */
- ret = gst_v4l2_buffer_pool_dqbuf (pool, &out);
+ ret = gst_v4l2_buffer_pool_dequeue (pool, &out);
if (ret == GST_FLOW_OK && out->pool == NULL)
/* release the rendered buffer back into the pool. This wakes up any
* thread waiting for a buffer in _acquire(). */
diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h
index 0fffc71..da23405 100644
--- a/sys/v4l2/gstv4l2bufferpool.h
+++ b/sys/v4l2/gstv4l2bufferpool.h
@@ -42,8 +42,8 @@
#define GST_V4L2_BUFFER_POOL_CAST(obj) ((GstV4l2BufferPool*)(obj))
/* This flow return is used to indicated that the last buffer of a
- * drain or a resoltuion change has been found. This should normally
- * only occure for mem-2-mem devices. */
+ * drain has been found. This should normally only occure for
+ * mem-2-mem devices. */
#define GST_V4L2_FLOW_LAST_BUFFER GST_FLOW_CUSTOM_SUCCESS
/* This flow return is used to indicated that the returned buffer was marked
@@ -51,6 +51,11 @@
* simply waiting for next buffer. */
#define GST_V4L2_FLOW_CORRUPTED_BUFFER GST_FLOW_CUSTOM_SUCCESS_1
+/* This flow return is used to indicated that the last buffer of a
+ * resoltuion change has been found. This should normally only
+ * occure for mem-2-mem devices. */
+#define GST_V4L2_FLOW_SOURCE_CHANGE GST_FLOW_CUSTOM_SUCCESS_2
+
struct _GstV4l2BufferPool
{
GstBufferPool parent;
diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c
index 124c778..9e1fe90 100644
--- a/sys/v4l2/gstv4l2object.c
+++ b/sys/v4l2/gstv4l2object.c
@@ -532,6 +532,10 @@
v4l2object->munmap = munmap;
}
+ v4l2object->poll = gst_poll_new (TRUE);
+ v4l2object->can_wait_event = FALSE;
+ v4l2object->can_poll_device = TRUE;
+
return v4l2object;
}
@@ -903,6 +907,14 @@
ret = gst_v4l2_dup (v4l2object, other);
+ if (ret && !V4L2_TYPE_IS_OUTPUT (v4l2object->type)) {
+ gst_poll_fd_init (&v4l2object->pollfd);
+ v4l2object->pollfd.fd = v4l2object->video_fd;
+ gst_poll_add_fd (v4l2object->poll, &v4l2object->pollfd);
+ /* used for dequeue event */
+ gst_poll_fd_ctl_read (v4l2object->poll, &v4l2object->pollfd, TRUE);
+ }
+
return ret;
}
@@ -3869,6 +3881,99 @@
return gst_v4l2_object_set_format_full (v4l2object, caps, TRUE, error);
}
+GstFlowReturn
+gst_v4l2_object_poll (GstV4l2Object * v4l2object)
+{
+ gint ret;
+
+ if (!v4l2object->can_poll_device)
+ goto done;
+
+ GST_LOG_OBJECT (v4l2object, "polling device");
+
+again:
+ ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
+ if (G_UNLIKELY (ret < 0)) {
+ switch (errno) {
+ case EBUSY:
+ goto stopped;
+ case EAGAIN:
+ case EINTR:
+ goto again;
+ case ENXIO:
+ GST_WARNING_OBJECT (v4l2object,
+ "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;
+
+done:
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+stopped:
+ {
+ GST_DEBUG_OBJECT (v4l2object, "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;
+ }
+}
+
+GstFlowReturn
+gst_v4l2_object_dqevent (GstV4l2Object * v4l2object)
+{
+ GstFlowReturn res;
+ struct v4l2_event evt;
+
+ GST_ERROR_OBJECT (v4l2object, "dequeueing a event");
+ if ((res = gst_v4l2_object_poll (v4l2object)) != GST_FLOW_OK)
+ goto poll_failed;
+
+ GST_ERROR_OBJECT (v4l2object, "1equeueing a event");
+
+ memset (&evt, 0x00, sizeof (struct v4l2_event));
+ if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DQEVENT, &evt) < 0)
+ goto dqevent_failed;
+
+ GST_ERROR_OBJECT (v4l2object, "2equeueing a event: %d", evt.type);
+ switch (evt.type)
+ {
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return GST_V4L2_FLOW_SOURCE_CHANGE;
+ break;
+ case V4L2_EVENT_EOS:
+ return GST_V4L2_FLOW_LAST_BUFFER;
+ break;
+ default:
+ break;
+ }
+
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+poll_failed:
+ {
+ GST_DEBUG_OBJECT (v4l2object, "poll error %s", gst_flow_get_name (res));
+ return res;
+ }
+dqevent_failed:
+ {
+ return GST_FLOW_ERROR;
+ }
+}
+
/**
* gst_v4l2_object_acquire_format:
* @v4l2object the object
@@ -4116,6 +4221,8 @@
GST_LOG_OBJECT (v4l2object->dbg_obj, "start flushing");
+ gst_poll_set_flushing (v4l2object->poll, TRUE);
+
if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
gst_buffer_pool_set_flushing (v4l2object->pool, TRUE);
@@ -4132,6 +4239,8 @@
if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
gst_buffer_pool_set_flushing (v4l2object->pool, FALSE);
+ gst_poll_set_flushing (v4l2object->poll, FALSE);
+
return ret;
}
@@ -4152,6 +4261,8 @@
v4l2object->pool = NULL;
}
+ gst_poll_free (v4l2object->poll);
+
GST_V4L2_SET_INACTIVE (v4l2object);
done:
diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h
index 7871eaf..11e8057 100644
--- a/sys/v4l2/gstv4l2object.h
+++ b/sys/v4l2/gstv4l2object.h
@@ -122,6 +122,9 @@
/* the video-device's file descriptor */
gint video_fd;
GstV4l2IOMode mode;
+ GstPoll *poll; /* a poll for video_fd */
+ GstPollFD pollfd;
+ gboolean can_poll_device;
gboolean active;
gboolean streaming;
@@ -208,6 +211,8 @@
* on slow USB firmwares. When this is set, gst_v4l2_set_format() will modify
* the caps to reflect what was negotiated during fixation */
gboolean skip_try_fmt_probes;
+ gboolean can_wait_event;
+ gboolean need_wait_event;
};
struct _GstV4l2ObjectClassHelper {
@@ -290,6 +295,7 @@
GstCaps * gst_v4l2_object_probe_caps (GstV4l2Object * v4l2object, GstCaps * filter);
GstCaps * gst_v4l2_object_get_caps (GstV4l2Object * v4l2object, GstCaps * filter);
+GstFlowReturn gst_v4l2_object_dqevent (GstV4l2Object * v4l2object);
gboolean gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info);
gboolean gst_v4l2_object_set_crop (GstV4l2Object * obj);
diff --git a/sys/v4l2/gstv4l2videodec.c b/sys/v4l2/gstv4l2videodec.c
index 838ebff..0da7210 100644
--- a/sys/v4l2/gstv4l2videodec.c
+++ b/sys/v4l2/gstv4l2videodec.c
@@ -457,72 +457,6 @@
return frame;
}
-static void
-gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
-{
- GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
- GstV4l2BufferPool *v4l2_pool = GST_V4L2_BUFFER_POOL (self->v4l2capture->pool);
- GstBufferPool *pool;
- GstVideoCodecFrame *frame;
- GstBuffer *buffer = NULL;
- GstFlowReturn ret;
-
- GST_LOG_OBJECT (decoder, "Allocate output buffer");
-
- self->output_flow = GST_FLOW_OK;
- do {
- /* We cannot use the base class allotate helper since it taking the internal
- * stream lock. we know that the acquire may need to poll until more frames
- * comes in and holding this lock would prevent that.
- */
- pool = gst_video_decoder_get_buffer_pool (decoder);
-
- /* Pool may be NULL if we started going to READY state */
- if (pool == NULL) {
- ret = GST_FLOW_FLUSHING;
- goto beach;
- }
-
- ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
- g_object_unref (pool);
-
- if (ret != GST_FLOW_OK)
- goto beach;
-
- GST_LOG_OBJECT (decoder, "Process output buffer");
- ret = gst_v4l2_buffer_pool_process (v4l2_pool, &buffer);
-
- } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER);
-
- if (ret != GST_FLOW_OK)
- goto beach;
-
- frame = gst_v4l2_video_dec_get_oldest_frame (decoder);
-
- if (frame) {
- frame->output_buffer = buffer;
- buffer = NULL;
- ret = gst_video_decoder_finish_frame (decoder, frame);
-
- if (ret != GST_FLOW_OK)
- goto beach;
- } else {
- GST_WARNING_OBJECT (decoder, "Decoder is producing too many buffers");
- gst_buffer_unref (buffer);
- }
-
- return;
-
-beach:
- GST_DEBUG_OBJECT (decoder, "Leaving output thread: %s",
- gst_flow_get_name (ret));
-
- gst_buffer_replace (&buffer, NULL);
- self->output_flow = ret;
- gst_v4l2_object_unlock (self->v4l2output);
- gst_pad_pause_task (decoder->srcpad);
-}
-
static gboolean
gst_v4l2_video_remove_padding (GstCapsFeatures * features,
GstStructure * structure, gpointer user_data)
@@ -557,74 +491,39 @@
return TRUE;
}
-static GstFlowReturn
-gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
- GstVideoCodecFrame * frame)
+static void
+gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
{
- GstV4l2Error error = GST_V4L2_ERROR_INIT;
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
- GstFlowReturn ret = GST_FLOW_OK;
- gboolean processed = FALSE;
- GstBuffer *tmp;
- GstTaskState task_state;
-
- GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);
-
- if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
- goto flushing;
-
- if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) {
- if (!self->input_state)
- goto not_negotiated;
- if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps,
- &error))
- goto not_negotiated;
- }
+ GstV4l2BufferPool *v4l2_pool;
+ GstBufferPool *pool;
+ GstVideoCodecFrame *frame;
+ GstBuffer *buffer = NULL;
+ GstFlowReturn ret;
if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
- GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
+ GstV4l2Error error = GST_V4L2_ERROR_INIT;
GstVideoInfo info;
GstVideoCodecState *output_state;
- GstBuffer *codec_data;
GstCaps *acquired_caps, *available_caps, *caps, *filter;
GstStructure *st;
- GST_DEBUG_OBJECT (self, "Sending header");
-
- codec_data = self->input_state->codec_data;
-
- /* We are running in byte-stream mode, so we don't know the headers, but
- * we need to send something, otherwise the decoder will refuse to
- * intialize.
- */
- if (codec_data) {
- gst_buffer_ref (codec_data);
- } else {
- codec_data = gst_buffer_ref (frame->input_buffer);
- processed = TRUE;
+ /* Wait until received SOURCE_CHANGE event to get right video format */
+ while (self->v4l2capture->can_wait_event
+ && self->v4l2capture->need_wait_event) {
+ ret = gst_v4l2_object_dqevent (self->v4l2capture);
+ if (ret == GST_V4L2_FLOW_SOURCE_CHANGE) {
+ GST_DEBUG_OBJECT (self, "Received source change event");
+ break;
+ } else if (ret == GST_V4L2_FLOW_LAST_BUFFER) {
+ GST_DEBUG_OBJECT (self, "Received eos event");
+ goto beach;
+ } else if (ret != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (self, "dqevent error");
+ goto beach;
+ }
}
-
- /* Ensure input internal pool is active */
- if (!gst_buffer_pool_is_active (pool)) {
- GstStructure *config = gst_buffer_pool_get_config (pool);
- gst_buffer_pool_config_set_params (config, self->input_state->caps,
- self->v4l2output->info.size, 2, 2);
-
- /* There is no reason to refuse this config */
- if (!gst_buffer_pool_set_config (pool, config))
- goto activate_failed;
-
- if (!gst_buffer_pool_set_active (pool, TRUE))
- goto activate_failed;
- }
-
- GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
- ret =
- gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
- v4l2output->pool), &codec_data);
- GST_VIDEO_DECODER_STREAM_LOCK (decoder);
-
- gst_buffer_unref (codec_data);
+ self->v4l2capture->need_wait_event = FALSE;
/* For decoders G_FMT returns coded size, G_SELECTION returns visible size
* in the compose rectangle. gst_v4l2_object_acquire_format() checks both
@@ -694,6 +593,155 @@
goto activate_failed;
}
+ GST_LOG_OBJECT (decoder, "Allocate output buffer");
+
+ v4l2_pool = GST_V4L2_BUFFER_POOL (self->v4l2capture->pool);
+
+ self->output_flow = GST_FLOW_OK;
+ do {
+ /* We cannot use the base class allotate helper since it taking the internal
+ * stream lock. we know that the acquire may need to poll until more frames
+ * comes in and holding this lock would prevent that.
+ */
+ pool = gst_video_decoder_get_buffer_pool (decoder);
+
+ /* Pool may be NULL if we started going to READY state */
+ if (pool == NULL) {
+ ret = GST_FLOW_FLUSHING;
+ goto beach;
+ }
+
+ ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
+ g_object_unref (pool);
+
+ if (ret != GST_FLOW_OK)
+ goto beach;
+
+ GST_LOG_OBJECT (decoder, "Process output buffer");
+ ret = gst_v4l2_buffer_pool_process (v4l2_pool, &buffer);
+ if (ret == GST_V4L2_FLOW_SOURCE_CHANGE) {
+ gst_v4l2_object_stop (self->v4l2capture);
+ return;
+ }
+ } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER);
+
+ if (ret != GST_FLOW_OK)
+ goto beach;
+
+ frame = gst_v4l2_video_dec_get_oldest_frame (decoder);
+
+ if (frame) {
+ frame->output_buffer = buffer;
+ buffer = NULL;
+ ret = gst_video_decoder_finish_frame (decoder, frame);
+
+ if (ret != GST_FLOW_OK)
+ goto beach;
+ } else {
+ GST_WARNING_OBJECT (decoder, "Decoder is producing too many buffers");
+ gst_buffer_unref (buffer);
+ }
+
+ return;
+
+/* ERRORS */
+not_negotiated:
+ {
+ GST_ERROR_OBJECT (self, "not negotiated");
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto beach;
+ }
+activate_failed:
+ {
+ GST_ERROR_OBJECT (self, "Buffer pool activation failed");
+ GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+ (_("Failed to allocate required memory.")),
+ ("Buffer pool activation failed"));
+ ret = GST_FLOW_ERROR;
+ goto beach;
+ }
+flushing:
+ {
+ ret = GST_FLOW_FLUSHING;
+ goto beach;
+ }
+beach:
+ GST_DEBUG_OBJECT (decoder, "Leaving output thread: %s",
+ gst_flow_get_name (ret));
+
+ gst_buffer_replace (&buffer, NULL);
+ self->output_flow = ret;
+ gst_v4l2_object_unlock (self->v4l2output);
+ gst_pad_pause_task (decoder->srcpad);
+}
+
+static GstFlowReturn
+gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
+ GstVideoCodecFrame * frame)
+{
+ GstV4l2Error error = GST_V4L2_ERROR_INIT;
+ GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+ GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
+ GstFlowReturn ret = GST_FLOW_OK;
+ gboolean processed = FALSE;
+ GstBuffer *tmp;
+ GstTaskState task_state;
+
+ GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);
+
+ if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
+ goto flushing;
+
+ if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) {
+ if (!self->input_state)
+ goto not_negotiated;
+ if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps,
+ &error))
+ goto not_negotiated;
+ }
+
+ if (G_UNLIKELY (!gst_buffer_pool_is_active (pool))) {
+ GstBuffer *codec_data;
+
+ GST_DEBUG_OBJECT (self, "Sending header");
+
+ codec_data = self->input_state->codec_data;
+
+ /* We are running in byte-stream mode, so we don't know the headers, but
+ * we need to send something, otherwise the decoder will refuse to
+ * intialize.
+ */
+ if (codec_data) {
+ gst_buffer_ref (codec_data);
+ } else {
+ codec_data = gst_buffer_ref (frame->input_buffer);
+ processed = TRUE;
+ }
+
+ /* Ensure input internal pool is active */
+ if (!gst_buffer_pool_is_active (pool)) {
+ GstStructure *config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set_params (config, self->input_state->caps,
+ self->v4l2output->info.size, 2, 2);
+
+ /* There is no reason to refuse this config */
+ if (!gst_buffer_pool_set_config (pool, config))
+ goto activate_failed;
+
+ if (!gst_buffer_pool_set_active (pool, TRUE))
+ goto activate_failed;
+ }
+
+ GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+ ret =
+ gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
+ v4l2output->pool), &codec_data);
+ GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+
+ gst_buffer_unref (codec_data);
+
+ }
+
task_state = gst_pad_get_task_state (GST_VIDEO_DECODER_SRC_PAD (self));
if (task_state == GST_TASK_STOPPED || task_state == GST_TASK_PAUSED) {
/* It's possible that the processing thread stopped due to an error */
@@ -961,6 +1009,9 @@
GST_OBJECT (GST_VIDEO_DECODER_SRC_PAD (self)),
V4L2_BUF_TYPE_VIDEO_CAPTURE, klass->default_device,
gst_v4l2_get_input, gst_v4l2_set_input, NULL);
+ self->v4l2capture->no_initial_format = TRUE;
+ self->v4l2capture->need_wait_event = TRUE;
+ self->v4l2output->keep_aspect = FALSE;
}
static void
diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c
index d3dbd42..51467fc 100644
--- a/sys/v4l2/v4l2_calls.c
+++ b/sys/v4l2/v4l2_calls.c
@@ -509,6 +509,42 @@
}
}
+gboolean
+gst_v4l2_subscribe_event (GstV4l2Object * v4l2object)
+{
+ GstElement *e;
+ struct v4l2_event_subscription sub;
+
+ e = v4l2object->element;
+
+ GST_DEBUG_OBJECT (e, "subscribe event");
+
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
+
+ memset(&sub, 0, sizeof(struct v4l2_event_subscription));
+ sub.type = V4L2_EVENT_SOURCE_CHANGE;
+ if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0)
+ goto failed;
+
+ sub.type = V4L2_EVENT_EOS;
+ if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0)
+ goto failed;
+
+ v4l2object->can_wait_event = TRUE;
+
+ return TRUE;
+
+ /* ERRORS */
+failed:
+ {
+ GST_WARNING_OBJECT (e, "Cannot subscribe V4L2_EVENT_SOURCE_CHANGE or "
+ "V4L2_EVENT_EOS event for device '%s'.",
+ v4l2object->videodev);
+ return TRUE;
+ }
+}
+
/******************************************************
* gst_v4l2_open():
* open the video device (v4l2object->videodev)
@@ -591,6 +627,10 @@
if (v4l2object->extra_controls)
gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
+ if (GST_IS_V4L2_VIDEO_DEC (v4l2object->element)) {
+ gst_v4l2_subscribe_event (v4l2object);
+ }
+
/* UVC devices are never interlaced, and doing VIDIOC_TRY_FMT on them
* causes expensive and slow USB IO, so don't probe them for interlaced
*/
@@ -689,6 +729,7 @@
v4l2object->never_interlaced = other->never_interlaced;
v4l2object->no_initial_format = other->no_initial_format;
+ v4l2object->can_wait_event = other->can_wait_event;
return TRUE;