mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-05 23:18:47 +00:00
reworked internal parameters a bit, added leaky-queue semantics
Original commit message from CVS: reworked internal parameters a bit, added leaky-queue semantics
This commit is contained in:
parent
fe0a39cf60
commit
d7e533b5ea
4 changed files with 208 additions and 102 deletions
138
gst/gstqueue.c
138
gst/gstqueue.c
|
@ -48,15 +48,22 @@ GstElementDetails gst_queue_details = {
|
||||||
|
|
||||||
/* Queue signals and args */
|
/* Queue signals and args */
|
||||||
enum {
|
enum {
|
||||||
/* FILL ME */
|
LOW_WATERMARK,
|
||||||
|
HIGH_WATERMARK,
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ARG_0,
|
ARG_0,
|
||||||
|
ARG_LEVEL_BUFFERS,
|
||||||
|
ARG_LEVEL_BYTES,
|
||||||
|
ARG_LEVEL_TIME,
|
||||||
|
ARG_SIZE_BUFFERS,
|
||||||
|
ARG_SIZE_BYTES,
|
||||||
|
ARG_SIZE_TIME,
|
||||||
|
ARG_LEAKY,
|
||||||
ARG_LEVEL,
|
ARG_LEVEL,
|
||||||
ARG_MAX_LEVEL,
|
ARG_MAX_LEVEL,
|
||||||
// ARG_BLOCK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,6 +84,23 @@ static void gst_queue_flush (GstQueue *queue);
|
||||||
|
|
||||||
static GstElementStateReturn gst_queue_change_state (GstElement *element);
|
static GstElementStateReturn gst_queue_change_state (GstElement *element);
|
||||||
|
|
||||||
|
|
||||||
|
static GtkType
|
||||||
|
queue_leaky_get_type(void) {
|
||||||
|
static GtkType queue_leaky_type = 0;
|
||||||
|
static GtkEnumValue queue_leaky[] = {
|
||||||
|
{ GST_QUEUE_NO_LEAK, "0", "Not Leaky" },
|
||||||
|
{ GST_QUEUE_LEAK_UPSTREAM, "1", "Leaky on Upstream" },
|
||||||
|
{ GST_QUEUE_LEAK_DOWNSTREAM, "2", "Leaky on Downstream" },
|
||||||
|
{ 0, NULL, NULL },
|
||||||
|
};
|
||||||
|
if (!queue_leaky_type) {
|
||||||
|
queue_leaky_type = gtk_type_register_enum("GstQueueLeaky", queue_leaky);
|
||||||
|
}
|
||||||
|
return queue_leaky_type;
|
||||||
|
}
|
||||||
|
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type())
|
||||||
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
static GstElementClass *parent_class = NULL;
|
||||||
//static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
|
//static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
@ -112,12 +136,12 @@ gst_queue_class_init (GstQueueClass *klass)
|
||||||
|
|
||||||
parent_class = gtk_type_class (GST_TYPE_ELEMENT);
|
parent_class = gtk_type_class (GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
|
gtk_object_add_arg_type ("GstQueue::leaky", GST_TYPE_QUEUE_LEAKY,
|
||||||
|
GTK_ARG_READWRITE, ARG_LEAKY);
|
||||||
gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
|
gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
|
||||||
GTK_ARG_READABLE, ARG_LEVEL);
|
GTK_ARG_READABLE, ARG_LEVEL);
|
||||||
gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
|
gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
|
||||||
GTK_ARG_READWRITE, ARG_MAX_LEVEL);
|
GTK_ARG_READWRITE, ARG_MAX_LEVEL);
|
||||||
// gtk_object_add_arg_type ("GstQueue::block", GTK_TYPE_BOOL,
|
|
||||||
// GTK_ARG_READWRITE, ARG_BLOCK);
|
|
||||||
|
|
||||||
gtkobject_class->set_arg = gst_queue_set_arg;
|
gtkobject_class->set_arg = gst_queue_set_arg;
|
||||||
gtkobject_class->get_arg = gst_queue_get_arg;
|
gtkobject_class->get_arg = gst_queue_get_arg;
|
||||||
|
@ -145,11 +169,11 @@ gst_queue_init (GstQueue *queue)
|
||||||
|
|
||||||
queue->queue = NULL;
|
queue->queue = NULL;
|
||||||
queue->level_buffers = 0;
|
queue->level_buffers = 0;
|
||||||
queue->max_buffers = 100;
|
|
||||||
// queue->block = TRUE;
|
|
||||||
queue->level_bytes = 0;
|
queue->level_bytes = 0;
|
||||||
queue->size_buffers = 0;
|
queue->level_time = 0LL;
|
||||||
queue->size_bytes = 0;
|
queue->size_buffers = 100; // 100 buffers
|
||||||
|
queue->size_bytes = 100 * 1024; // 100KB
|
||||||
|
queue->size_time = 1000000000LL; // 1sec
|
||||||
|
|
||||||
queue->emptycond = g_cond_new ();
|
queue->emptycond = g_cond_new ();
|
||||||
queue->fullcond = g_cond_new ();
|
queue->fullcond = g_cond_new ();
|
||||||
|
@ -259,50 +283,72 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf)
|
||||||
|
|
||||||
/* we have to lock the queue since we span threads */
|
/* we have to lock the queue since we span threads */
|
||||||
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"try have queue lock\n");
|
// GST_DEBUG (GST_CAT_DATAFLOW,"trying to get lock on queue \"%s\"\n",name);
|
||||||
GST_LOCK (queue);
|
GST_LOCK (queue);
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s adding buffer %p %ld\n", name, buf, pthread_self ());
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"have queue lock\n");
|
|
||||||
|
|
||||||
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
|
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
|
||||||
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "buffer has FLUSH bit set, flushing queue\n");
|
||||||
gst_queue_flush (queue);
|
gst_queue_flush (queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s: chain %d %p\n", name, queue->level_buffers, buf);
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "adding buffer %p of size %d\n",buf,GST_BUFFER_SIZE(buf));
|
||||||
|
|
||||||
while (queue->level_buffers >= queue->max_buffers) {
|
if (queue->level_buffers >= queue->size_buffers) {
|
||||||
// if there's a pending state change for this queue or its manager, switch
|
// if this is a leaky queue...
|
||||||
// back to iterator so bottom half of state change executes
|
if (queue->leaky) {
|
||||||
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
|
// if we leak on the upstream side, drop the current buffer
|
||||||
GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
|
if (queue->leaky == GST_QUEUE_LEAK_UPSTREAM) {
|
||||||
{
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end\n");
|
||||||
GST_UNLOCK(queue);
|
gst_buffer_unref(buf);
|
||||||
cothread_switch(cothread_current_main());
|
// now we have to clean up and exit right away
|
||||||
|
GST_UNLOCK (queue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// otherwise we have to push a buffer off the other end
|
||||||
|
else {
|
||||||
|
GSList *front;
|
||||||
|
GstBuffer *leakbuf;
|
||||||
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end\n");
|
||||||
|
front = queue->queue;
|
||||||
|
leakbuf = (GstBuffer *)(front->data);
|
||||||
|
queue->level_buffers--;
|
||||||
|
queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
|
||||||
|
gst_buffer_unref(leakbuf);
|
||||||
|
queue->queue = g_slist_remove_link (queue->queue, front);
|
||||||
|
g_slist_free (front);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s waiting %d\n", name, queue->level_buffers);
|
while (queue->level_buffers >= queue->size_buffers) {
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s: O\n", name);
|
// if there's a pending state change for this queue or its manager, switch
|
||||||
g_cond_signal (queue->emptycond);
|
// back to iterator so bottom half of state change executes
|
||||||
g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
|
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
|
||||||
STATUS("%s: O+\n");
|
GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s waiting done %d\n", name, queue->level_buffers);
|
{
|
||||||
|
GST_UNLOCK(queue);
|
||||||
|
cothread_switch(cothread_current_main());
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for space, level is %d\n", queue->level_buffers);
|
||||||
|
g_cond_signal (queue->emptycond);
|
||||||
|
g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
|
||||||
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "done waiting, level is now %d\n", queue->level_buffers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put the buffer on the tail of the list */
|
/* put the buffer on the tail of the list */
|
||||||
queue->queue = g_slist_append (queue->queue, buf);
|
queue->queue = g_slist_append (queue->queue, buf);
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)+\n",GST_DEBUG_PAD_NAME(pad));
|
queue->level_buffers++;
|
||||||
|
queue->level_bytes += GST_BUFFER_SIZE(buf);
|
||||||
|
// GST_DEBUG (GST_CAT_DATAFLOW, "(%s:%s)+\n",GST_DEBUG_PAD_NAME(pad));
|
||||||
|
|
||||||
/* if we were empty, but aren't any more, signal a condition */
|
/* if we were empty, but aren't any more, signal a condition */
|
||||||
queue->level_buffers++;
|
|
||||||
// if (queue->level_buffers >= 0)
|
|
||||||
if (queue->level_buffers == 1)
|
if (queue->level_buffers == 1)
|
||||||
{
|
{
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
|
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
|
||||||
g_cond_signal (queue->emptycond);
|
g_cond_signal (queue->emptycond);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s chain %d end signal(%d,%p)\n", name, queue->level_buffers, tosignal, queue->emptycond);
|
|
||||||
|
|
||||||
GST_UNLOCK (queue);
|
GST_UNLOCK (queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,13 +374,6 @@ gst_queue_get (GstPad *pad)
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
|
GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
|
GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
|
||||||
|
|
||||||
// we bail if there's nothing there
|
|
||||||
// g_assert(queue->block);
|
|
||||||
// if (!queue->level_buffers && !queue->block) {
|
|
||||||
// GST_UNLOCK(queue);
|
|
||||||
// return NULL;
|
|
||||||
// }
|
|
||||||
|
|
||||||
while (!queue->level_buffers) {
|
while (!queue->level_buffers) {
|
||||||
if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
|
if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
|
GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
|
||||||
|
@ -363,14 +402,15 @@ gst_queue_get (GstPad *pad)
|
||||||
queue->queue = g_slist_remove_link (queue->queue, front);
|
queue->queue = g_slist_remove_link (queue->queue, front);
|
||||||
g_slist_free (front);
|
g_slist_free (front);
|
||||||
|
|
||||||
// if (queue->level_buffers < queue->max_buffers)
|
// if (queue->level_buffers < queue->size_buffers)
|
||||||
if (queue->level_buffers == queue->max_buffers)
|
if (queue->level_buffers == queue->size_buffers)
|
||||||
{
|
{
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
|
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
|
||||||
g_cond_signal (queue->fullcond);
|
g_cond_signal (queue->fullcond);
|
||||||
}
|
}
|
||||||
|
|
||||||
queue->level_buffers--;
|
queue->level_buffers--;
|
||||||
|
queue->level_bytes -= GST_BUFFER_SIZE(buf);
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
|
GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
|
||||||
|
|
||||||
GST_UNLOCK(queue);
|
GST_UNLOCK(queue);
|
||||||
|
@ -450,12 +490,12 @@ gst_queue_set_arg (GtkObject *object, GtkArg *arg, guint id)
|
||||||
queue = GST_QUEUE (object);
|
queue = GST_QUEUE (object);
|
||||||
|
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case ARG_MAX_LEVEL:
|
case ARG_LEAKY:
|
||||||
queue->max_buffers = GTK_VALUE_INT (*arg);
|
queue->leaky = GTK_VALUE_INT (*arg);
|
||||||
|
break;
|
||||||
|
case ARG_MAX_LEVEL:
|
||||||
|
queue->size_buffers = GTK_VALUE_INT (*arg);
|
||||||
break;
|
break;
|
||||||
// case ARG_BLOCK:
|
|
||||||
// queue->block = GTK_VALUE_BOOL (*arg);
|
|
||||||
// break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -472,15 +512,15 @@ gst_queue_get_arg (GtkObject *object, GtkArg *arg, guint id)
|
||||||
queue = GST_QUEUE (object);
|
queue = GST_QUEUE (object);
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
|
case ARG_LEAKY:
|
||||||
|
GTK_VALUE_INT (*arg) = queue->leaky;
|
||||||
|
break;
|
||||||
case ARG_LEVEL:
|
case ARG_LEVEL:
|
||||||
GTK_VALUE_INT (*arg) = queue->level_buffers;
|
GTK_VALUE_INT (*arg) = queue->level_buffers;
|
||||||
break;
|
break;
|
||||||
case ARG_MAX_LEVEL:
|
case ARG_MAX_LEVEL:
|
||||||
GTK_VALUE_INT (*arg) = queue->max_buffers;
|
GTK_VALUE_INT (*arg) = queue->size_buffers;
|
||||||
break;
|
break;
|
||||||
// case ARG_BLOCK:
|
|
||||||
// GTK_VALUE_BOOL (*arg) = queue->block;
|
|
||||||
// break;
|
|
||||||
default:
|
default:
|
||||||
arg->type = GTK_TYPE_INVALID;
|
arg->type = GTK_TYPE_INVALID;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -47,6 +47,12 @@ GstElementDetails gst_queue_details;
|
||||||
#define GST_IS_QUEUE_CLASS(obj) \
|
#define GST_IS_QUEUE_CLASS(obj) \
|
||||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
|
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GST_QUEUE_NO_LEAK = 0,
|
||||||
|
GST_QUEUE_LEAK_UPSTREAM = 1,
|
||||||
|
GST_QUEUE_LEAK_DOWNSTREAM = 2
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct _GstQueue GstQueue;
|
typedef struct _GstQueue GstQueue;
|
||||||
typedef struct _GstQueueClass GstQueueClass;
|
typedef struct _GstQueueClass GstQueueClass;
|
||||||
|
|
||||||
|
@ -60,11 +66,14 @@ struct _GstQueue {
|
||||||
GSList *queue;
|
GSList *queue;
|
||||||
|
|
||||||
gint level_buffers; /* number of buffers queued here */
|
gint level_buffers; /* number of buffers queued here */
|
||||||
gint max_buffers; /* maximum number of buffers queued here */
|
|
||||||
// gboolean block; /* if set to FALSE, _get returns NULL if queue empty */
|
|
||||||
gint level_bytes; /* number of bytes queued here */
|
gint level_bytes; /* number of bytes queued here */
|
||||||
|
guint64 level_time; /* amount of time queued here */
|
||||||
|
|
||||||
gint size_buffers; /* size of queue in buffers */
|
gint size_buffers; /* size of queue in buffers */
|
||||||
gint size_bytes; /* size of queue in bytes */
|
gint size_bytes; /* size of queue in bytes */
|
||||||
|
guint64 size_time; /* size of queue in time */
|
||||||
|
|
||||||
|
gint leaky; /* whether the queue is leaky, and if so at which end */
|
||||||
|
|
||||||
GCond *emptycond;
|
GCond *emptycond;
|
||||||
GCond *fullcond;
|
GCond *fullcond;
|
||||||
|
@ -74,6 +83,10 @@ struct _GstQueue {
|
||||||
|
|
||||||
struct _GstQueueClass {
|
struct _GstQueueClass {
|
||||||
GstElementClass parent_class;
|
GstElementClass parent_class;
|
||||||
|
|
||||||
|
/* signal callbacks */
|
||||||
|
void (*low_watermark) (GstQueue *queue, gint level);
|
||||||
|
void (*high_watermark) (GstQueue *queue, gint level);
|
||||||
};
|
};
|
||||||
|
|
||||||
GtkType gst_queue_get_type (void);
|
GtkType gst_queue_get_type (void);
|
||||||
|
|
|
@ -48,15 +48,22 @@ GstElementDetails gst_queue_details = {
|
||||||
|
|
||||||
/* Queue signals and args */
|
/* Queue signals and args */
|
||||||
enum {
|
enum {
|
||||||
/* FILL ME */
|
LOW_WATERMARK,
|
||||||
|
HIGH_WATERMARK,
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ARG_0,
|
ARG_0,
|
||||||
|
ARG_LEVEL_BUFFERS,
|
||||||
|
ARG_LEVEL_BYTES,
|
||||||
|
ARG_LEVEL_TIME,
|
||||||
|
ARG_SIZE_BUFFERS,
|
||||||
|
ARG_SIZE_BYTES,
|
||||||
|
ARG_SIZE_TIME,
|
||||||
|
ARG_LEAKY,
|
||||||
ARG_LEVEL,
|
ARG_LEVEL,
|
||||||
ARG_MAX_LEVEL,
|
ARG_MAX_LEVEL,
|
||||||
// ARG_BLOCK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,6 +84,23 @@ static void gst_queue_flush (GstQueue *queue);
|
||||||
|
|
||||||
static GstElementStateReturn gst_queue_change_state (GstElement *element);
|
static GstElementStateReturn gst_queue_change_state (GstElement *element);
|
||||||
|
|
||||||
|
|
||||||
|
static GtkType
|
||||||
|
queue_leaky_get_type(void) {
|
||||||
|
static GtkType queue_leaky_type = 0;
|
||||||
|
static GtkEnumValue queue_leaky[] = {
|
||||||
|
{ GST_QUEUE_NO_LEAK, "0", "Not Leaky" },
|
||||||
|
{ GST_QUEUE_LEAK_UPSTREAM, "1", "Leaky on Upstream" },
|
||||||
|
{ GST_QUEUE_LEAK_DOWNSTREAM, "2", "Leaky on Downstream" },
|
||||||
|
{ 0, NULL, NULL },
|
||||||
|
};
|
||||||
|
if (!queue_leaky_type) {
|
||||||
|
queue_leaky_type = gtk_type_register_enum("GstQueueLeaky", queue_leaky);
|
||||||
|
}
|
||||||
|
return queue_leaky_type;
|
||||||
|
}
|
||||||
|
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type())
|
||||||
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
static GstElementClass *parent_class = NULL;
|
||||||
//static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
|
//static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
@ -112,12 +136,12 @@ gst_queue_class_init (GstQueueClass *klass)
|
||||||
|
|
||||||
parent_class = gtk_type_class (GST_TYPE_ELEMENT);
|
parent_class = gtk_type_class (GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
|
gtk_object_add_arg_type ("GstQueue::leaky", GST_TYPE_QUEUE_LEAKY,
|
||||||
|
GTK_ARG_READWRITE, ARG_LEAKY);
|
||||||
gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
|
gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
|
||||||
GTK_ARG_READABLE, ARG_LEVEL);
|
GTK_ARG_READABLE, ARG_LEVEL);
|
||||||
gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
|
gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
|
||||||
GTK_ARG_READWRITE, ARG_MAX_LEVEL);
|
GTK_ARG_READWRITE, ARG_MAX_LEVEL);
|
||||||
// gtk_object_add_arg_type ("GstQueue::block", GTK_TYPE_BOOL,
|
|
||||||
// GTK_ARG_READWRITE, ARG_BLOCK);
|
|
||||||
|
|
||||||
gtkobject_class->set_arg = gst_queue_set_arg;
|
gtkobject_class->set_arg = gst_queue_set_arg;
|
||||||
gtkobject_class->get_arg = gst_queue_get_arg;
|
gtkobject_class->get_arg = gst_queue_get_arg;
|
||||||
|
@ -145,11 +169,11 @@ gst_queue_init (GstQueue *queue)
|
||||||
|
|
||||||
queue->queue = NULL;
|
queue->queue = NULL;
|
||||||
queue->level_buffers = 0;
|
queue->level_buffers = 0;
|
||||||
queue->max_buffers = 100;
|
|
||||||
// queue->block = TRUE;
|
|
||||||
queue->level_bytes = 0;
|
queue->level_bytes = 0;
|
||||||
queue->size_buffers = 0;
|
queue->level_time = 0LL;
|
||||||
queue->size_bytes = 0;
|
queue->size_buffers = 100; // 100 buffers
|
||||||
|
queue->size_bytes = 100 * 1024; // 100KB
|
||||||
|
queue->size_time = 1000000000LL; // 1sec
|
||||||
|
|
||||||
queue->emptycond = g_cond_new ();
|
queue->emptycond = g_cond_new ();
|
||||||
queue->fullcond = g_cond_new ();
|
queue->fullcond = g_cond_new ();
|
||||||
|
@ -259,50 +283,72 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf)
|
||||||
|
|
||||||
/* we have to lock the queue since we span threads */
|
/* we have to lock the queue since we span threads */
|
||||||
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"try have queue lock\n");
|
// GST_DEBUG (GST_CAT_DATAFLOW,"trying to get lock on queue \"%s\"\n",name);
|
||||||
GST_LOCK (queue);
|
GST_LOCK (queue);
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s adding buffer %p %ld\n", name, buf, pthread_self ());
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"have queue lock\n");
|
|
||||||
|
|
||||||
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
|
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
|
||||||
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "buffer has FLUSH bit set, flushing queue\n");
|
||||||
gst_queue_flush (queue);
|
gst_queue_flush (queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s: chain %d %p\n", name, queue->level_buffers, buf);
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "adding buffer %p of size %d\n",buf,GST_BUFFER_SIZE(buf));
|
||||||
|
|
||||||
while (queue->level_buffers >= queue->max_buffers) {
|
if (queue->level_buffers >= queue->size_buffers) {
|
||||||
// if there's a pending state change for this queue or its manager, switch
|
// if this is a leaky queue...
|
||||||
// back to iterator so bottom half of state change executes
|
if (queue->leaky) {
|
||||||
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
|
// if we leak on the upstream side, drop the current buffer
|
||||||
GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
|
if (queue->leaky == GST_QUEUE_LEAK_UPSTREAM) {
|
||||||
{
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end\n");
|
||||||
GST_UNLOCK(queue);
|
gst_buffer_unref(buf);
|
||||||
cothread_switch(cothread_current_main());
|
// now we have to clean up and exit right away
|
||||||
|
GST_UNLOCK (queue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// otherwise we have to push a buffer off the other end
|
||||||
|
else {
|
||||||
|
GSList *front;
|
||||||
|
GstBuffer *leakbuf;
|
||||||
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end\n");
|
||||||
|
front = queue->queue;
|
||||||
|
leakbuf = (GstBuffer *)(front->data);
|
||||||
|
queue->level_buffers--;
|
||||||
|
queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
|
||||||
|
gst_buffer_unref(leakbuf);
|
||||||
|
queue->queue = g_slist_remove_link (queue->queue, front);
|
||||||
|
g_slist_free (front);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s waiting %d\n", name, queue->level_buffers);
|
while (queue->level_buffers >= queue->size_buffers) {
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s: O\n", name);
|
// if there's a pending state change for this queue or its manager, switch
|
||||||
g_cond_signal (queue->emptycond);
|
// back to iterator so bottom half of state change executes
|
||||||
g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
|
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
|
||||||
STATUS("%s: O+\n");
|
GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s waiting done %d\n", name, queue->level_buffers);
|
{
|
||||||
|
GST_UNLOCK(queue);
|
||||||
|
cothread_switch(cothread_current_main());
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for space, level is %d\n", queue->level_buffers);
|
||||||
|
g_cond_signal (queue->emptycond);
|
||||||
|
g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
|
||||||
|
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "done waiting, level is now %d\n", queue->level_buffers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put the buffer on the tail of the list */
|
/* put the buffer on the tail of the list */
|
||||||
queue->queue = g_slist_append (queue->queue, buf);
|
queue->queue = g_slist_append (queue->queue, buf);
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)+\n",GST_DEBUG_PAD_NAME(pad));
|
queue->level_buffers++;
|
||||||
|
queue->level_bytes += GST_BUFFER_SIZE(buf);
|
||||||
|
// GST_DEBUG (GST_CAT_DATAFLOW, "(%s:%s)+\n",GST_DEBUG_PAD_NAME(pad));
|
||||||
|
|
||||||
/* if we were empty, but aren't any more, signal a condition */
|
/* if we were empty, but aren't any more, signal a condition */
|
||||||
queue->level_buffers++;
|
|
||||||
// if (queue->level_buffers >= 0)
|
|
||||||
if (queue->level_buffers == 1)
|
if (queue->level_buffers == 1)
|
||||||
{
|
{
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
|
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
|
||||||
g_cond_signal (queue->emptycond);
|
g_cond_signal (queue->emptycond);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s chain %d end signal(%d,%p)\n", name, queue->level_buffers, tosignal, queue->emptycond);
|
|
||||||
|
|
||||||
GST_UNLOCK (queue);
|
GST_UNLOCK (queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,13 +374,6 @@ gst_queue_get (GstPad *pad)
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
|
GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
|
GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
|
||||||
|
|
||||||
// we bail if there's nothing there
|
|
||||||
// g_assert(queue->block);
|
|
||||||
// if (!queue->level_buffers && !queue->block) {
|
|
||||||
// GST_UNLOCK(queue);
|
|
||||||
// return NULL;
|
|
||||||
// }
|
|
||||||
|
|
||||||
while (!queue->level_buffers) {
|
while (!queue->level_buffers) {
|
||||||
if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
|
if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
|
GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
|
||||||
|
@ -363,14 +402,15 @@ gst_queue_get (GstPad *pad)
|
||||||
queue->queue = g_slist_remove_link (queue->queue, front);
|
queue->queue = g_slist_remove_link (queue->queue, front);
|
||||||
g_slist_free (front);
|
g_slist_free (front);
|
||||||
|
|
||||||
// if (queue->level_buffers < queue->max_buffers)
|
// if (queue->level_buffers < queue->size_buffers)
|
||||||
if (queue->level_buffers == queue->max_buffers)
|
if (queue->level_buffers == queue->size_buffers)
|
||||||
{
|
{
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
|
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
|
||||||
g_cond_signal (queue->fullcond);
|
g_cond_signal (queue->fullcond);
|
||||||
}
|
}
|
||||||
|
|
||||||
queue->level_buffers--;
|
queue->level_buffers--;
|
||||||
|
queue->level_bytes -= GST_BUFFER_SIZE(buf);
|
||||||
GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
|
GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
|
||||||
|
|
||||||
GST_UNLOCK(queue);
|
GST_UNLOCK(queue);
|
||||||
|
@ -450,12 +490,12 @@ gst_queue_set_arg (GtkObject *object, GtkArg *arg, guint id)
|
||||||
queue = GST_QUEUE (object);
|
queue = GST_QUEUE (object);
|
||||||
|
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case ARG_MAX_LEVEL:
|
case ARG_LEAKY:
|
||||||
queue->max_buffers = GTK_VALUE_INT (*arg);
|
queue->leaky = GTK_VALUE_INT (*arg);
|
||||||
|
break;
|
||||||
|
case ARG_MAX_LEVEL:
|
||||||
|
queue->size_buffers = GTK_VALUE_INT (*arg);
|
||||||
break;
|
break;
|
||||||
// case ARG_BLOCK:
|
|
||||||
// queue->block = GTK_VALUE_BOOL (*arg);
|
|
||||||
// break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -472,15 +512,15 @@ gst_queue_get_arg (GtkObject *object, GtkArg *arg, guint id)
|
||||||
queue = GST_QUEUE (object);
|
queue = GST_QUEUE (object);
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
|
case ARG_LEAKY:
|
||||||
|
GTK_VALUE_INT (*arg) = queue->leaky;
|
||||||
|
break;
|
||||||
case ARG_LEVEL:
|
case ARG_LEVEL:
|
||||||
GTK_VALUE_INT (*arg) = queue->level_buffers;
|
GTK_VALUE_INT (*arg) = queue->level_buffers;
|
||||||
break;
|
break;
|
||||||
case ARG_MAX_LEVEL:
|
case ARG_MAX_LEVEL:
|
||||||
GTK_VALUE_INT (*arg) = queue->max_buffers;
|
GTK_VALUE_INT (*arg) = queue->size_buffers;
|
||||||
break;
|
break;
|
||||||
// case ARG_BLOCK:
|
|
||||||
// GTK_VALUE_BOOL (*arg) = queue->block;
|
|
||||||
// break;
|
|
||||||
default:
|
default:
|
||||||
arg->type = GTK_TYPE_INVALID;
|
arg->type = GTK_TYPE_INVALID;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -47,6 +47,12 @@ GstElementDetails gst_queue_details;
|
||||||
#define GST_IS_QUEUE_CLASS(obj) \
|
#define GST_IS_QUEUE_CLASS(obj) \
|
||||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
|
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GST_QUEUE_NO_LEAK = 0,
|
||||||
|
GST_QUEUE_LEAK_UPSTREAM = 1,
|
||||||
|
GST_QUEUE_LEAK_DOWNSTREAM = 2
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct _GstQueue GstQueue;
|
typedef struct _GstQueue GstQueue;
|
||||||
typedef struct _GstQueueClass GstQueueClass;
|
typedef struct _GstQueueClass GstQueueClass;
|
||||||
|
|
||||||
|
@ -60,11 +66,14 @@ struct _GstQueue {
|
||||||
GSList *queue;
|
GSList *queue;
|
||||||
|
|
||||||
gint level_buffers; /* number of buffers queued here */
|
gint level_buffers; /* number of buffers queued here */
|
||||||
gint max_buffers; /* maximum number of buffers queued here */
|
|
||||||
// gboolean block; /* if set to FALSE, _get returns NULL if queue empty */
|
|
||||||
gint level_bytes; /* number of bytes queued here */
|
gint level_bytes; /* number of bytes queued here */
|
||||||
|
guint64 level_time; /* amount of time queued here */
|
||||||
|
|
||||||
gint size_buffers; /* size of queue in buffers */
|
gint size_buffers; /* size of queue in buffers */
|
||||||
gint size_bytes; /* size of queue in bytes */
|
gint size_bytes; /* size of queue in bytes */
|
||||||
|
guint64 size_time; /* size of queue in time */
|
||||||
|
|
||||||
|
gint leaky; /* whether the queue is leaky, and if so at which end */
|
||||||
|
|
||||||
GCond *emptycond;
|
GCond *emptycond;
|
||||||
GCond *fullcond;
|
GCond *fullcond;
|
||||||
|
@ -74,6 +83,10 @@ struct _GstQueue {
|
||||||
|
|
||||||
struct _GstQueueClass {
|
struct _GstQueueClass {
|
||||||
GstElementClass parent_class;
|
GstElementClass parent_class;
|
||||||
|
|
||||||
|
/* signal callbacks */
|
||||||
|
void (*low_watermark) (GstQueue *queue, gint level);
|
||||||
|
void (*high_watermark) (GstQueue *queue, gint level);
|
||||||
};
|
};
|
||||||
|
|
||||||
GtkType gst_queue_get_type (void);
|
GtkType gst_queue_get_type (void);
|
||||||
|
|
Loading…
Reference in a new issue