mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +00:00
multiqueue: Add mode to synchronize deactivated/not-linked streams by the running time
Fixes bug #645107, #600648.
This commit is contained in:
parent
4a836cae9f
commit
9f83109706
2 changed files with 196 additions and 9 deletions
|
@ -156,6 +156,8 @@ struct _GstSingleQueue
|
||||||
guint32 nextid; /* ID of the next object waiting to be pushed */
|
guint32 nextid; /* ID of the next object waiting to be pushed */
|
||||||
guint32 oldid; /* ID of the last object pushed (last in a series) */
|
guint32 oldid; /* ID of the last object pushed (last in a series) */
|
||||||
guint32 last_oldid; /* Previously observed old_id, reset to MAXUINT32 on flush */
|
guint32 last_oldid; /* Previously observed old_id, reset to MAXUINT32 on flush */
|
||||||
|
GstClockTime next_time; /* End running time of next buffer to be pushed */
|
||||||
|
GstClockTime last_time; /* Start running time of last pushed buffer */
|
||||||
GCond *turn; /* SingleQueue turn waiting conditional */
|
GCond *turn; /* SingleQueue turn waiting conditional */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -179,6 +181,7 @@ static void gst_single_queue_free (GstSingleQueue * squeue);
|
||||||
|
|
||||||
static void wake_up_next_non_linked (GstMultiQueue * mq);
|
static void wake_up_next_non_linked (GstMultiQueue * mq);
|
||||||
static void compute_high_id (GstMultiQueue * mq);
|
static void compute_high_id (GstMultiQueue * mq);
|
||||||
|
static void compute_high_time (GstMultiQueue * mq);
|
||||||
static void single_queue_overrun_cb (GstDataQueue * dq, GstSingleQueue * sq);
|
static void single_queue_overrun_cb (GstDataQueue * dq, GstSingleQueue * sq);
|
||||||
static void single_queue_underrun_cb (GstDataQueue * dq, GstSingleQueue * sq);
|
static void single_queue_underrun_cb (GstDataQueue * dq, GstSingleQueue * sq);
|
||||||
|
|
||||||
|
@ -224,6 +227,7 @@ enum
|
||||||
#define DEFAULT_USE_BUFFERING FALSE
|
#define DEFAULT_USE_BUFFERING FALSE
|
||||||
#define DEFAULT_LOW_PERCENT 10
|
#define DEFAULT_LOW_PERCENT 10
|
||||||
#define DEFAULT_HIGH_PERCENT 99
|
#define DEFAULT_HIGH_PERCENT 99
|
||||||
|
#define DEFAULT_SYNC_BY_RUNNING_TIME FALSE
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -237,6 +241,7 @@ enum
|
||||||
PROP_USE_BUFFERING,
|
PROP_USE_BUFFERING,
|
||||||
PROP_LOW_PERCENT,
|
PROP_LOW_PERCENT,
|
||||||
PROP_HIGH_PERCENT,
|
PROP_HIGH_PERCENT,
|
||||||
|
PROP_SYNC_BY_RUNNING_TIME,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -396,6 +401,22 @@ gst_multi_queue_class_init (GstMultiQueueClass * klass)
|
||||||
"High threshold for buffering to finish", 0, 100,
|
"High threshold for buffering to finish", 0, 100,
|
||||||
DEFAULT_HIGH_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
DEFAULT_HIGH_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstMultiQueue:sync-by-running-time
|
||||||
|
*
|
||||||
|
* If enabled multiqueue will synchronize deactivated or not-linked streams
|
||||||
|
* to the activated and linked streams by taking the running time.
|
||||||
|
* Otherwise multiqueue will synchronize the deactivated or not-linked
|
||||||
|
* streams by keeping the order in which buffers and events arrived compared
|
||||||
|
* to active and linked streams.
|
||||||
|
*
|
||||||
|
* Since: 0.10.33
|
||||||
|
*/
|
||||||
|
g_object_class_install_property (gobject_class, PROP_SYNC_BY_RUNNING_TIME,
|
||||||
|
g_param_spec_boolean ("sync-by-running-time", "Sync By Running Time",
|
||||||
|
"Synchronize deactivated or not-linked streams by running time",
|
||||||
|
DEFAULT_SYNC_BY_RUNNING_TIME,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
gobject_class->finalize = gst_multi_queue_finalize;
|
gobject_class->finalize = gst_multi_queue_finalize;
|
||||||
|
|
||||||
|
@ -425,8 +446,11 @@ gst_multi_queue_init (GstMultiQueue * mqueue, GstMultiQueueClass * klass)
|
||||||
mqueue->low_percent = DEFAULT_LOW_PERCENT;
|
mqueue->low_percent = DEFAULT_LOW_PERCENT;
|
||||||
mqueue->high_percent = DEFAULT_HIGH_PERCENT;
|
mqueue->high_percent = DEFAULT_HIGH_PERCENT;
|
||||||
|
|
||||||
|
mqueue->sync_by_running_time = DEFAULT_SYNC_BY_RUNNING_TIME;
|
||||||
|
|
||||||
mqueue->counter = 1;
|
mqueue->counter = 1;
|
||||||
mqueue->highid = -1;
|
mqueue->highid = -1;
|
||||||
|
mqueue->high_time = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
mqueue->qlock = g_mutex_new ();
|
mqueue->qlock = g_mutex_new ();
|
||||||
}
|
}
|
||||||
|
@ -499,6 +523,9 @@ gst_multi_queue_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_HIGH_PERCENT:
|
case PROP_HIGH_PERCENT:
|
||||||
mq->high_percent = g_value_get_int (value);
|
mq->high_percent = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_SYNC_BY_RUNNING_TIME:
|
||||||
|
mq->sync_by_running_time = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -541,6 +568,9 @@ gst_multi_queue_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_HIGH_PERCENT:
|
case PROP_HIGH_PERCENT:
|
||||||
g_value_set_int (value, mq->high_percent);
|
g_value_set_int (value, mq->high_percent);
|
||||||
break;
|
break;
|
||||||
|
case PROP_SYNC_BY_RUNNING_TIME:
|
||||||
|
g_value_set_boolean (value, mq->sync_by_running_time);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -740,8 +770,15 @@ gst_single_queue_flush (GstMultiQueue * mq, GstSingleQueue * sq, gboolean flush)
|
||||||
sq->nextid = 0;
|
sq->nextid = 0;
|
||||||
sq->oldid = 0;
|
sq->oldid = 0;
|
||||||
sq->last_oldid = G_MAXUINT32;
|
sq->last_oldid = G_MAXUINT32;
|
||||||
|
sq->next_time = GST_CLOCK_TIME_NONE;
|
||||||
|
sq->last_time = GST_CLOCK_TIME_NONE;
|
||||||
gst_data_queue_set_flushing (sq->queue, FALSE);
|
gst_data_queue_set_flushing (sq->queue, FALSE);
|
||||||
|
|
||||||
|
/* Reset high time to be recomputed next */
|
||||||
|
GST_MULTI_QUEUE_MUTEX_LOCK (mq);
|
||||||
|
mq->high_time = GST_CLOCK_TIME_NONE;
|
||||||
|
GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
|
||||||
|
|
||||||
sq->flushing = FALSE;
|
sq->flushing = FALSE;
|
||||||
|
|
||||||
GST_LOG_OBJECT (mq, "SingleQueue %d : starting task", sq->id);
|
GST_LOG_OBJECT (mq, "SingleQueue %d : starting task", sq->id);
|
||||||
|
@ -946,6 +983,71 @@ apply_buffer (GstMultiQueue * mq, GstSingleQueue * sq, GstClockTime timestamp,
|
||||||
GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
|
GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstClockTime
|
||||||
|
get_running_time (GstSegment * segment, GstMiniObject * object, gboolean end)
|
||||||
|
{
|
||||||
|
GstClockTime time = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
if (GST_IS_BUFFER (object)) {
|
||||||
|
GstBuffer *buf = GST_BUFFER_CAST (object);
|
||||||
|
|
||||||
|
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||||
|
time = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
if (end && GST_BUFFER_DURATION_IS_VALID (buf))
|
||||||
|
time += GST_BUFFER_DURATION (buf);
|
||||||
|
if (time > segment->stop)
|
||||||
|
time = segment->stop;
|
||||||
|
time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, time);
|
||||||
|
}
|
||||||
|
} else if (GST_IS_BUFFER_LIST (object)) {
|
||||||
|
GstBufferList *list = GST_BUFFER_LIST_CAST (object);
|
||||||
|
GstBufferListIterator *it = gst_buffer_list_iterate (list);
|
||||||
|
GstBuffer *buf;
|
||||||
|
|
||||||
|
do {
|
||||||
|
while ((buf = gst_buffer_list_iterator_next (it))) {
|
||||||
|
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||||
|
time = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
if (end && GST_BUFFER_DURATION_IS_VALID (buf))
|
||||||
|
time += GST_BUFFER_DURATION (buf);
|
||||||
|
if (time > segment->stop)
|
||||||
|
time = segment->stop;
|
||||||
|
time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, time);
|
||||||
|
if (!end)
|
||||||
|
goto done;
|
||||||
|
} else if (!end) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (gst_buffer_list_iterator_next_group (it));
|
||||||
|
} else if (GST_IS_EVENT (object)) {
|
||||||
|
GstEvent *event = GST_EVENT_CAST (object);
|
||||||
|
|
||||||
|
/* For newsegment events return the running time of the start position */
|
||||||
|
if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
|
||||||
|
GstSegment new_segment = *segment;
|
||||||
|
gboolean update;
|
||||||
|
gdouble rate, applied_rate;
|
||||||
|
GstFormat format;
|
||||||
|
gint64 start, stop, position;
|
||||||
|
|
||||||
|
gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
|
||||||
|
&format, &start, &stop, &position);
|
||||||
|
if (format == GST_FORMAT_TIME) {
|
||||||
|
gst_segment_set_newsegment_full (&new_segment, update, rate,
|
||||||
|
applied_rate, format, start, stop, position);
|
||||||
|
|
||||||
|
time =
|
||||||
|
gst_segment_to_running_time (&new_segment, GST_FORMAT_TIME,
|
||||||
|
new_segment.start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_single_queue_push_one (GstMultiQueue * mq, GstSingleQueue * sq,
|
gst_single_queue_push_one (GstMultiQueue * mq, GstSingleQueue * sq,
|
||||||
GstMiniObject * object)
|
GstMiniObject * object)
|
||||||
|
@ -1078,6 +1180,7 @@ gst_multi_queue_loop (GstPad * pad)
|
||||||
GstMiniObject *object = NULL;
|
GstMiniObject *object = NULL;
|
||||||
guint32 newid;
|
guint32 newid;
|
||||||
GstFlowReturn result;
|
GstFlowReturn result;
|
||||||
|
GstClockTime next_time;
|
||||||
|
|
||||||
sq = (GstSingleQueue *) gst_pad_get_element_private (pad);
|
sq = (GstSingleQueue *) gst_pad_get_element_private (pad);
|
||||||
mq = sq->mqueue;
|
mq = sq->mqueue;
|
||||||
|
@ -1099,6 +1202,9 @@ gst_multi_queue_loop (GstPad * pad)
|
||||||
object = gst_multi_queue_item_steal_object (item);
|
object = gst_multi_queue_item_steal_object (item);
|
||||||
gst_multi_queue_item_destroy (item);
|
gst_multi_queue_item_destroy (item);
|
||||||
|
|
||||||
|
/* Get running time of the item. Events will have GST_CLOCK_TIME_NONE */
|
||||||
|
next_time = get_running_time (&sq->src_segment, object, TRUE);
|
||||||
|
|
||||||
GST_LOG_OBJECT (mq, "SingleQueue %d : newid:%d , oldid:%d",
|
GST_LOG_OBJECT (mq, "SingleQueue %d : newid:%d , oldid:%d",
|
||||||
sq->id, newid, sq->last_oldid);
|
sq->id, newid, sq->last_oldid);
|
||||||
|
|
||||||
|
@ -1107,9 +1213,9 @@ gst_multi_queue_loop (GstPad * pad)
|
||||||
* or it's the first loop, or we just passed the previous highid,
|
* or it's the first loop, or we just passed the previous highid,
|
||||||
* we might need to wake some sleeping pad up, so there's extra work
|
* we might need to wake some sleeping pad up, so there's extra work
|
||||||
* there too */
|
* there too */
|
||||||
if (sq->srcresult == GST_FLOW_NOT_LINKED ||
|
if (sq->srcresult == GST_FLOW_NOT_LINKED
|
||||||
(sq->last_oldid == G_MAXUINT32) || (newid != (sq->last_oldid + 1)) ||
|
|| (sq->last_oldid == G_MAXUINT32) || (newid != (sq->last_oldid + 1))
|
||||||
sq->last_oldid > mq->highid) {
|
|| sq->last_oldid > mq->highid) {
|
||||||
GST_LOG_OBJECT (mq, "CHECKING sq->srcresult: %s",
|
GST_LOG_OBJECT (mq, "CHECKING sq->srcresult: %s",
|
||||||
gst_flow_get_name (sq->srcresult));
|
gst_flow_get_name (sq->srcresult));
|
||||||
|
|
||||||
|
@ -1124,6 +1230,7 @@ gst_multi_queue_loop (GstPad * pad)
|
||||||
|
|
||||||
/* Update the nextid so other threads know when to wake us up */
|
/* Update the nextid so other threads know when to wake us up */
|
||||||
sq->nextid = newid;
|
sq->nextid = newid;
|
||||||
|
sq->next_time = next_time;
|
||||||
|
|
||||||
/* Update the oldid (the last ID we output) for highid tracking */
|
/* Update the oldid (the last ID we output) for highid tracking */
|
||||||
if (sq->last_oldid != G_MAXUINT32)
|
if (sq->last_oldid != G_MAXUINT32)
|
||||||
|
@ -1134,10 +1241,20 @@ gst_multi_queue_loop (GstPad * pad)
|
||||||
|
|
||||||
/* Recompute the highid */
|
/* Recompute the highid */
|
||||||
compute_high_id (mq);
|
compute_high_id (mq);
|
||||||
while (newid > mq->highid && sq->srcresult == GST_FLOW_NOT_LINKED) {
|
/* Recompute the high time */
|
||||||
GST_DEBUG_OBJECT (mq, "queue %d sleeping for not-linked wakeup with "
|
compute_high_time (mq);
|
||||||
"newid %u and highid %u", sq->id, newid, mq->highid);
|
|
||||||
|
|
||||||
|
while (((mq->sync_by_running_time && next_time != GST_CLOCK_TIME_NONE &&
|
||||||
|
(mq->high_time == GST_CLOCK_TIME_NONE
|
||||||
|
|| next_time >= mq->high_time))
|
||||||
|
|| (!mq->sync_by_running_time && newid > mq->highid))
|
||||||
|
&& sq->srcresult == GST_FLOW_NOT_LINKED) {
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (mq,
|
||||||
|
"queue %d sleeping for not-linked wakeup with "
|
||||||
|
"newid %u, highid %u, next_time %" GST_TIME_FORMAT
|
||||||
|
", high_time %" GST_TIME_FORMAT, sq->id, newid, mq->highid,
|
||||||
|
GST_TIME_ARGS (next_time), GST_TIME_ARGS (mq->high_time));
|
||||||
|
|
||||||
/* Wake up all non-linked pads before we sleep */
|
/* Wake up all non-linked pads before we sleep */
|
||||||
wake_up_next_non_linked (mq);
|
wake_up_next_non_linked (mq);
|
||||||
|
@ -1151,8 +1268,13 @@ gst_multi_queue_loop (GstPad * pad)
|
||||||
goto out_flushing;
|
goto out_flushing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Recompute the high time */
|
||||||
|
compute_high_time (mq);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mq, "queue %d woken from sleeping for not-linked "
|
GST_DEBUG_OBJECT (mq, "queue %d woken from sleeping for not-linked "
|
||||||
"wakeup with newid %u and highid %u", sq->id, newid, mq->highid);
|
"wakeup with newid %u, highid %u, next_time %" GST_TIME_FORMAT
|
||||||
|
", high_time %" GST_TIME_FORMAT, sq->id, newid, mq->highid,
|
||||||
|
GST_TIME_ARGS (next_time), GST_TIME_ARGS (mq->high_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-compute the high_id in case someone else pushed */
|
/* Re-compute the high_id in case someone else pushed */
|
||||||
|
@ -1162,8 +1284,9 @@ gst_multi_queue_loop (GstPad * pad)
|
||||||
/* Wake up all non-linked pads */
|
/* Wake up all non-linked pads */
|
||||||
wake_up_next_non_linked (mq);
|
wake_up_next_non_linked (mq);
|
||||||
}
|
}
|
||||||
/* We're done waiting, we can clear the nextid */
|
/* We're done waiting, we can clear the nextid and nexttime */
|
||||||
sq->nextid = 0;
|
sq->nextid = 0;
|
||||||
|
sq->next_time = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
|
GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
|
||||||
}
|
}
|
||||||
|
@ -1174,6 +1297,18 @@ gst_multi_queue_loop (GstPad * pad)
|
||||||
GST_LOG_OBJECT (mq, "BEFORE PUSHING sq->srcresult: %s",
|
GST_LOG_OBJECT (mq, "BEFORE PUSHING sq->srcresult: %s",
|
||||||
gst_flow_get_name (sq->srcresult));
|
gst_flow_get_name (sq->srcresult));
|
||||||
|
|
||||||
|
/* Update time stats */
|
||||||
|
next_time = get_running_time (&sq->src_segment, object, FALSE);
|
||||||
|
if (next_time != GST_CLOCK_TIME_NONE) {
|
||||||
|
if (sq->last_time == GST_CLOCK_TIME_NONE || sq->last_time < next_time)
|
||||||
|
sq->last_time = next_time;
|
||||||
|
if (mq->high_time == GST_CLOCK_TIME_NONE || mq->high_time <= next_time) {
|
||||||
|
/* Wake up all non-linked pads now that we advanceed the high time */
|
||||||
|
mq->high_time = next_time;
|
||||||
|
wake_up_next_non_linked (mq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to push out the new object */
|
/* Try to push out the new object */
|
||||||
result = gst_single_queue_push_one (mq, sq, object);
|
result = gst_single_queue_push_one (mq, sq, object);
|
||||||
sq->srcresult = result;
|
sq->srcresult = result;
|
||||||
|
@ -1187,6 +1322,7 @@ gst_multi_queue_loop (GstPad * pad)
|
||||||
gst_flow_get_name (sq->srcresult));
|
gst_flow_get_name (sq->srcresult));
|
||||||
|
|
||||||
sq->last_oldid = newid;
|
sq->last_oldid = newid;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
out_flushing:
|
out_flushing:
|
||||||
|
@ -1516,7 +1652,10 @@ wake_up_next_non_linked (GstMultiQueue * mq)
|
||||||
GstSingleQueue *sq = (GstSingleQueue *) tmp->data;
|
GstSingleQueue *sq = (GstSingleQueue *) tmp->data;
|
||||||
|
|
||||||
if (sq->srcresult == GST_FLOW_NOT_LINKED) {
|
if (sq->srcresult == GST_FLOW_NOT_LINKED) {
|
||||||
if (sq->nextid != 0 && sq->nextid <= mq->highid) {
|
if ((mq->sync_by_running_time && mq->high_time != GST_CLOCK_TIME_NONE
|
||||||
|
&& sq->next_time != GST_CLOCK_TIME_NONE
|
||||||
|
&& sq->next_time >= mq->high_time)
|
||||||
|
|| (sq->nextid != 0 && sq->nextid <= mq->highid)) {
|
||||||
GST_LOG_OBJECT (mq, "Waking up singlequeue %d", sq->id);
|
GST_LOG_OBJECT (mq, "Waking up singlequeue %d", sq->id);
|
||||||
g_cond_signal (sq->turn);
|
g_cond_signal (sq->turn);
|
||||||
}
|
}
|
||||||
|
@ -1567,6 +1706,49 @@ compute_high_id (GstMultiQueue * mq)
|
||||||
lowest);
|
lowest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* WITH LOCK TAKEN */
|
||||||
|
static void
|
||||||
|
compute_high_time (GstMultiQueue * mq)
|
||||||
|
{
|
||||||
|
/* The high-id is either the highest id among the linked pads, or if all
|
||||||
|
* pads are not-linked, it's the lowest not-linked pad */
|
||||||
|
GList *tmp;
|
||||||
|
GstClockTime highest = GST_CLOCK_TIME_NONE;
|
||||||
|
GstClockTime lowest = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
for (tmp = mq->queues; tmp; tmp = g_list_next (tmp)) {
|
||||||
|
GstSingleQueue *sq = (GstSingleQueue *) tmp->data;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (mq,
|
||||||
|
"inspecting sq:%d , next_time:%" GST_TIME_FORMAT ", last_time:%"
|
||||||
|
GST_TIME_FORMAT ", srcresult:%s", sq->id, GST_TIME_ARGS (sq->next_time),
|
||||||
|
GST_TIME_ARGS (sq->last_time), gst_flow_get_name (sq->srcresult));
|
||||||
|
|
||||||
|
if (sq->srcresult == GST_FLOW_NOT_LINKED) {
|
||||||
|
/* No need to consider queues which are not waiting */
|
||||||
|
if (sq->next_time == GST_CLOCK_TIME_NONE) {
|
||||||
|
GST_LOG_OBJECT (mq, "sq:%d is not waiting - ignoring", sq->id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowest == GST_CLOCK_TIME_NONE || sq->next_time < lowest)
|
||||||
|
lowest = sq->next_time;
|
||||||
|
} else if (sq->srcresult != GST_FLOW_UNEXPECTED) {
|
||||||
|
/* If we don't have a global highid, or the global highid is lower than
|
||||||
|
* this single queue's last outputted id, store the queue's one,
|
||||||
|
* unless the singlequeue is at EOS (srcresult = UNEXPECTED) */
|
||||||
|
if (highest == GST_CLOCK_TIME_NONE || sq->last_time > highest)
|
||||||
|
highest = sq->last_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mq->high_time = highest;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (mq,
|
||||||
|
"High time is now : %" GST_TIME_FORMAT ", lowest non-linked %"
|
||||||
|
GST_TIME_FORMAT, GST_TIME_ARGS (mq->high_time), GST_TIME_ARGS (lowest));
|
||||||
|
}
|
||||||
|
|
||||||
#define IS_FILLED(q, format, value) (((q)->max_size.format) != 0 && \
|
#define IS_FILLED(q, format, value) (((q)->max_size.format) != 0 && \
|
||||||
((q)->max_size.format) <= (value))
|
((q)->max_size.format) <= (value))
|
||||||
|
|
||||||
|
@ -1770,6 +1952,8 @@ gst_single_queue_new (GstMultiQueue * mqueue, gint id)
|
||||||
|
|
||||||
sq->nextid = 0;
|
sq->nextid = 0;
|
||||||
sq->oldid = 0;
|
sq->oldid = 0;
|
||||||
|
sq->next_time = GST_CLOCK_TIME_NONE;
|
||||||
|
sq->last_time = GST_CLOCK_TIME_NONE;
|
||||||
sq->turn = g_cond_new ();
|
sq->turn = g_cond_new ();
|
||||||
|
|
||||||
sq->sinktime = GST_CLOCK_TIME_NONE;
|
sq->sinktime = GST_CLOCK_TIME_NONE;
|
||||||
|
|
|
@ -50,6 +50,8 @@ typedef struct _GstMultiQueueClass GstMultiQueueClass;
|
||||||
struct _GstMultiQueue {
|
struct _GstMultiQueue {
|
||||||
GstElement element;
|
GstElement element;
|
||||||
|
|
||||||
|
gboolean sync_by_running_time;
|
||||||
|
|
||||||
/* number of queues */
|
/* number of queues */
|
||||||
guint nbqueues;
|
guint nbqueues;
|
||||||
|
|
||||||
|
@ -65,6 +67,7 @@ struct _GstMultiQueue {
|
||||||
|
|
||||||
guint32 counter; /* incoming object counter, use atomic accesses */
|
guint32 counter; /* incoming object counter, use atomic accesses */
|
||||||
guint32 highid; /* contains highest id of last outputted object */
|
guint32 highid; /* contains highest id of last outputted object */
|
||||||
|
GstClockTime high_time; /* highest start running time */
|
||||||
|
|
||||||
GMutex * qlock; /* Global queue lock (vs object lock or individual */
|
GMutex * qlock; /* Global queue lock (vs object lock or individual */
|
||||||
/* queues lock). Protects nbqueues, queues, global */
|
/* queues lock). Protects nbqueues, queues, global */
|
||||||
|
|
Loading…
Reference in a new issue