mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
basesrc: Add public gst_base_src_negotiate () function
This is useful for when format changes occur mid-stream.
This commit is contained in:
parent
27fbaf9d44
commit
6412988975
3 changed files with 115 additions and 3 deletions
|
@ -360,7 +360,7 @@ static GstFlowReturn gst_base_src_getrange (GstPad * pad, GstObject * parent,
|
|||
static GstFlowReturn gst_base_src_get_range (GstBaseSrc * src, guint64 offset,
|
||||
guint length, GstBuffer ** buf);
|
||||
static gboolean gst_base_src_seekable (GstBaseSrc * src);
|
||||
static gboolean gst_base_src_negotiate (GstBaseSrc * basesrc);
|
||||
static gboolean gst_base_src_negotiate_unlocked (GstBaseSrc * basesrc);
|
||||
static gboolean gst_base_src_update_length (GstBaseSrc * src, guint64 offset,
|
||||
guint * length, gboolean force);
|
||||
|
||||
|
@ -2804,7 +2804,7 @@ gst_base_src_loop (GstPad * pad)
|
|||
|
||||
/* check if we need to renegotiate */
|
||||
if (gst_pad_check_reconfigure (pad)) {
|
||||
if (!gst_base_src_negotiate (src)) {
|
||||
if (!gst_base_src_negotiate_unlocked (src)) {
|
||||
gst_pad_mark_reconfigure (pad);
|
||||
if (GST_PAD_IS_FLUSHING (pad)) {
|
||||
GST_LIVE_LOCK (src);
|
||||
|
@ -3374,7 +3374,7 @@ no_caps:
|
|||
}
|
||||
|
||||
static gboolean
|
||||
gst_base_src_negotiate (GstBaseSrc * basesrc)
|
||||
gst_base_src_negotiate_unlocked (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstBaseSrcClass *bclass;
|
||||
gboolean result;
|
||||
|
@ -3401,6 +3401,39 @@ gst_base_src_negotiate (GstBaseSrc * basesrc)
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_base_src_negotiate:
|
||||
* @basesrc: base source instance
|
||||
*
|
||||
* Negotiates src pad caps with downstream elements.
|
||||
* Unmarks GST_PAD_FLAG_NEED_RECONFIGURE in any case. But marks it again
|
||||
* if #GstBaseSrcClass.negotiate() fails.
|
||||
*
|
||||
* Do not call this in the #GstBaseSrcClass.fill() vmethod. Call this in
|
||||
* #GstBaseSrcClass.create() or in #GstBaseSrcClass.alloc(), _before_ any
|
||||
* buffer is allocated.
|
||||
*
|
||||
* Returns: %TRUE if the negotiation succeeded, else %FALSE.
|
||||
*
|
||||
* Since: 1.18
|
||||
*/
|
||||
gboolean
|
||||
gst_base_src_negotiate (GstBaseSrc * src)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
|
||||
g_return_val_if_fail (GST_IS_BASE_SRC (src), FALSE);
|
||||
|
||||
GST_PAD_STREAM_LOCK (src->srcpad);
|
||||
gst_pad_check_reconfigure (src->srcpad);
|
||||
ret = gst_base_src_negotiate_unlocked (src);
|
||||
if (!ret)
|
||||
gst_pad_mark_reconfigure (src->srcpad);
|
||||
GST_PAD_STREAM_UNLOCK (src->srcpad);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_base_src_start (GstBaseSrc * basesrc)
|
||||
{
|
||||
|
|
|
@ -275,6 +275,9 @@ void gst_base_src_set_async (GstBaseSrc *src, gboolean async);
|
|||
GST_BASE_API
|
||||
gboolean gst_base_src_is_async (GstBaseSrc *src);
|
||||
|
||||
GST_BASE_API
|
||||
gboolean gst_base_src_negotiate (GstBaseSrc *src);
|
||||
|
||||
GST_BASE_API
|
||||
void gst_base_src_start_complete (GstBaseSrc * basesrc, GstFlowReturn ret);
|
||||
|
||||
|
|
|
@ -909,6 +909,8 @@ typedef struct
|
|||
GstBaseSrc parent;
|
||||
GstSegment *segment;
|
||||
gboolean n_output_buffers;
|
||||
gsize num_times_negotiate_called;
|
||||
gboolean do_renegotiate;
|
||||
} TimeSrc;
|
||||
|
||||
typedef GstBaseSrcClass TimeSrcClass;
|
||||
|
@ -923,6 +925,8 @@ time_src_init (TimeSrc * src)
|
|||
gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
|
||||
gst_base_src_set_automatic_eos (GST_BASE_SRC (src), FALSE);
|
||||
src->n_output_buffers = 0;
|
||||
src->num_times_negotiate_called = 0;
|
||||
src->do_renegotiate = FALSE;
|
||||
}
|
||||
|
||||
/* This test src outputs a compressed format, with a single GOP
|
||||
|
@ -941,6 +945,11 @@ time_src_create (GstBaseSrc * bsrc, guint64 offset, guint size,
|
|||
if (src->segment->position >= src->segment->stop)
|
||||
return GST_FLOW_EOS;
|
||||
|
||||
if (src->do_renegotiate) {
|
||||
gst_base_src_negotiate (bsrc);
|
||||
src->do_renegotiate = FALSE;
|
||||
}
|
||||
|
||||
*p_buf = gst_buffer_new ();
|
||||
GST_BUFFER_PTS (*p_buf) = src->segment->position;
|
||||
GST_BUFFER_DURATION (*p_buf) = GST_SECOND;
|
||||
|
@ -973,6 +982,14 @@ time_src_is_seekable (GstBaseSrc * bsrc)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
time_src_negotiate (GstBaseSrc * bsrc)
|
||||
{
|
||||
TimeSrc *src = (TimeSrc *) bsrc;
|
||||
src->num_times_negotiate_called++;
|
||||
return GST_BASE_SRC_CLASS (time_src_parent_class)->negotiate (bsrc);
|
||||
}
|
||||
|
||||
static void
|
||||
time_src_class_init (TimeSrcClass * klass)
|
||||
{
|
||||
|
@ -984,6 +1001,7 @@ time_src_class_init (TimeSrcClass * klass)
|
|||
gstbasesrc_class->create = time_src_create;
|
||||
gstbasesrc_class->do_seek = time_src_do_seek;
|
||||
gstbasesrc_class->is_seekable = time_src_is_seekable;
|
||||
gstbasesrc_class->negotiate = time_src_negotiate;
|
||||
}
|
||||
|
||||
GST_START_TEST (basesrc_time_automatic_eos)
|
||||
|
@ -1033,6 +1051,63 @@ GST_START_TEST (basesrc_time_automatic_eos)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (basesrc_negotiate)
|
||||
{
|
||||
GstElement *src, *sink;
|
||||
GstElement *pipe;
|
||||
GstSegment seg;
|
||||
|
||||
src = g_object_new (time_src_get_type (), NULL);
|
||||
sink = gst_element_factory_make ("fakesink", NULL);
|
||||
|
||||
pipe = gst_pipeline_new (NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (pipe), src);
|
||||
gst_bin_add (GST_BIN (pipe), sink);
|
||||
|
||||
gst_element_link (src, sink);
|
||||
|
||||
/* Use some default segment to get the stream going. */
|
||||
gst_segment_init (&seg, GST_FORMAT_TIME);
|
||||
((TimeSrc *) src)->segment = gst_segment_copy (&seg);
|
||||
|
||||
/* Check that gst_base_src_negotiate () actually ends up calling
|
||||
* the negotiate () vmethod by first running the test pipeline
|
||||
* normally, and then running it with a gst_base_src_negotiate ()
|
||||
* call, and checking how many times negotiate () was called in
|
||||
* both cases. */
|
||||
|
||||
/* Run pipeline, keep do_renegotiate at FALSE, so
|
||||
* gst_base_src_negotiate () won't be called. negotiate () still
|
||||
* will be called once, as part of the regular caps negotiation
|
||||
* sequence. */
|
||||
fail_unless (((TimeSrc *) src)->num_times_negotiate_called == 0);
|
||||
gst_element_set_state (pipe, GST_STATE_PLAYING);
|
||||
gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
|
||||
fail_unless (((TimeSrc *) src)->num_times_negotiate_called == 1);
|
||||
gst_element_set_state (pipe, GST_STATE_NULL);
|
||||
|
||||
((TimeSrc *) src)->num_times_negotiate_called = 0;
|
||||
|
||||
/* Run pipeline, set do_renegotiate to TRUE. This will cause
|
||||
* negotiate () to be called twice: Once during caps negotiation,
|
||||
* and once by the gst_base_src_negotiate () call in the
|
||||
* time_src_create () function. */
|
||||
((TimeSrc *) src)->do_renegotiate = TRUE;
|
||||
fail_unless (((TimeSrc *) src)->num_times_negotiate_called == 0);
|
||||
gst_element_set_state (pipe, GST_STATE_PLAYING);
|
||||
gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
|
||||
fail_unless (((TimeSrc *) src)->num_times_negotiate_called == 2);
|
||||
gst_element_set_state (pipe, GST_STATE_NULL);
|
||||
|
||||
if (((TimeSrc *) src)->segment)
|
||||
gst_segment_free (((TimeSrc *) src)->segment);
|
||||
|
||||
gst_object_unref (pipe);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
gst_basesrc_suite (void)
|
||||
{
|
||||
|
@ -1050,6 +1125,7 @@ gst_basesrc_suite (void)
|
|||
tcase_add_test (tc, basesrc_seek_on_last_buffer);
|
||||
tcase_add_test (tc, basesrc_create_bufferlist);
|
||||
tcase_add_test (tc, basesrc_time_automatic_eos);
|
||||
tcase_add_test (tc, basesrc_negotiate);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue