AC_SUBST(GHTTP_LIBS)
AC_SUBST(GST_HTTPSRC_GET_TYPE)
-dnl Check for X11 extensions
-AC_PATH_XTRA
-if test "-DX_DISPLAY_MISSING" = "$X_CFLAGS"; then
- AC_MSG_ERROR(can not find X11)
-fi
-AC_SUBST(X_CFLAGS)
-AC_SUBST(X_PRE_LIBS)
-AC_SUBST(X_EXTRA_LIBS)
-AC_SUBST(X_LIBS)
-
-AC_CHECK_LIB(Xv, XvQueryExtension,,,
- $X_LIBS $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS)
-
dnl Check for atomic.h
dnl Note: use AC_CHECK_HEADER not AC_CHECK_HEADERS, because the latter
dnl defines the wrong default symbol as well (HAVE_ASM_ATOMIC_H)
AC_MSG_RESULT(no)
)
+dnl Check for X11 extensions
+AC_PATH_XTRA
+if test "-DX_DISPLAY_MISSING" = "$X_CFLAGS"; then
+ AC_MSG_ERROR(can not find X11)
+fi
+AC_SUBST(X_CFLAGS)
+AC_SUBST(X_PRE_LIBS)
+AC_SUBST(X_EXTRA_LIBS)
+AC_SUBST(X_LIBS)
+
+AC_CHECK_LIB(Xv, XvQueryExtension,,,
+ $X_LIBS $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS)
+
dnl Check for xaudio
AC_CHECK_HEADER(xaudio/decoder.h,[
AC_DEFINE(HAVE_XAUDIO)
--- /dev/null
+Since the plan generation only happens as a result of the state mechanism,
+I'll describe that first.
+
+It's supposed to be recursive, such that setting the state on a Bin
+recursively sets all the children. However, this needs to be rethought
+somewhat, in light of some recent ideas on the actual definition of some
+of the states.
+
+The mechanism is thus: When you call gst_element_set_state(element,state),
+it calls the change_state() class method. The basic Element-provided
+version just sets or unsets the state. A more complex element like the
+audiosink will switch on the state and do certain things like open or
+close the sound card on transition to/from various states. The success or
+failure of these actions can determine whether or not the state gets
+[un]set as requested.
+
+GtkObject signals enter in here, as whenever a state is successfully
+changed, the STATE_CHANGE signal is fired, which gives higher-level code
+the ability to do something based on the change.
+
+The Bin's change_state function walks through all its children and sets
+their state. This is where things get interesting, and where things are
+going to need to be changed.
+
+The issue is what the states are and mean. Currently the states are as
+follows (from gstelement.h):
+
+typedef enum {
+ GST_STATE_COMPLETE = (1 << 0),
+ GST_STATE_RUNNING = (1 << 1),
+ GST_STATE_DISCOVERY = (1 << 2),
+ GST_STATE_PREROLL = (1 << 3),
+
+ GST_STATE_PLAYING = (1 << 4),
+ GST_STATE_PAUSED = (1 << 5),
+
+ GST_STATE_MAX = (1 << 15),
+} GstElementState;
+
+COMPLETE means all the necesary information is available to run, i.e. the
+filename for the disksrc, etc. RUNNING means that it's actually doing
+something, but that's fuzzy. PLAYING means there really is data flowing
+through the graph, where PAUSED temporary stops the flow. PLAYING &&
+PAUSED is the same idea as !PLAYING, but there are probably going to be
+many cases where there really is a distinction.
+
+DISCOVERY is intended for the autoconnect case, in those instances where
+the only way to determine the input or output type of some pad is for an
+element to actually process some data. The idea in that case is that the
+source element would be responsible for sending the data non-destructively
+(in the case of a network client, it would have to save it all up, unless
+it has seek capabilities over the network), and all downstream elements
+process it in such a way as to not hose their own state. Or rather, when
+they cease to do discovery, they completely wipe their state as if nothing
+ever happened.
+
+PREROLL is a local state, used for things like sending the first half of
+an MPEG GOP through the decoder in order to start playback at a frame
+somewhere in the middle of said GOP. Not sure how that will work,
+exactly.
+
+
+The issue is that these states aren't layered, and it most certainly isn't
+the case that a container isn't able to be of a certain state unless all
+of its children are. I guess I should explain the idea of reconfigurable
+pipelines:
+
+Build an MP3 player, give it the ability to use audio effects plugins.
+Since you don't want to have to start the stream over again (especially if
+it's a network stream) every time you change the effect. This means you
+need to be able to freeze the pipeline in place to change it, without
+taking too much time.
+
+This matters when you consider that certain state changes should render
+various state bits invalid. In the FROZEN state these won't happen,
+because the assumption is that they're temporary.
+
+If you haven't noticed by now, the state system isn't entirely
+self-consistent yet. It needs work, and it needs discussion.
audiosink->fd = -1;
audiosink->clock = gst_clock_get_system();
gst_clock_register(audiosink->clock, GST_OBJECT(audiosink));
- audiosink->clocktime = 0LL;
+ //audiosink->clocktime = 0LL;
- gst_element_set_state(GST_ELEMENT(audiosink),GST_STATE_COMPLETE);
}
void gst_audiosink_sync_parms(GstAudioSink *audiosink) {
audiosink->frequency,audiosink->format,
(audiosink->channels == 2) ? "stereo" : "mono",ospace.bytes, frag);
-
}
GstElement *gst_audiosink_new(gchar *name) {
GstElement *audiosink = GST_ELEMENT(gtk_type_new(GST_TYPE_AUDIOSINK));
gst_element_set_name(GST_ELEMENT(audiosink),name);
+ gst_element_set_state(GST_ELEMENT(audiosink),GST_STATE_COMPLETE);
return audiosink;
}
void gst_audiosink_chain(GstPad *pad,GstBuffer *buf) {
GstAudioSink *audiosink;
MetaAudioRaw *meta;
- count_info info;
+ gboolean in_flush;
+ audio_buf_info ospace;
g_return_if_fail(pad != NULL);
g_return_if_fail(GST_IS_PAD(pad));
audiosink = GST_AUDIOSINK(pad->parent);
// g_return_if_fail(GST_FLAG_IS_SET(audiosink,GST_STATE_RUNNING));
+ if (in_flush = GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLUSH)) {
+ DEBUG("audiosink: flush\n");
+ ioctl(audiosink->fd,SNDCTL_DSP_RESET,0);
+ }
+
+
meta = (MetaAudioRaw *)gst_buffer_get_first_meta(buf);
if (meta != NULL) {
if ((meta->format != audiosink->format) ||
gst_trace_add_entry(NULL,0,buf,"audiosink: writing to soundcard");
//g_print("audiosink: writing to soundcard\n");
if (audiosink->fd > 2) {
- if (audiosink->clocktime == 0LL)
- gst_clock_wait(audiosink->clock, audiosink->clocktime, GST_OBJECT(audiosink));
- ioctl(audiosink->fd,SNDCTL_DSP_GETOPTR,&info);
- audiosink->clocktime = (info.bytes*1000000LL)/(audiosink->frequency*audiosink->channels);
- //g_print("audiosink: bytes sent %d time %llu\n", info.bytes, audiosink->clocktime);
- gst_clock_set(audiosink->clock, audiosink->clocktime);
- if (!audiosink->mute)
- write(audiosink->fd,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
- //audiosink->clocktime += (1000000LL*GST_BUFFER_SIZE(buf)/(audiosink->channels*
-// (audiosink->format/8)*(audiosink->frequency)));
- //g_print("audiosink: writing to soundcard ok\n");
+ if (!audiosink->mute) {
+ if (gst_clock_current_diff(audiosink->clock, GST_BUFFER_TIMESTAMP(buf)) > 500000) {
+ }
+ else {
+ gst_clock_wait(audiosink->clock, GST_BUFFER_TIMESTAMP(buf), GST_OBJECT(audiosink));
+ ioctl(audiosink->fd,SNDCTL_DSP_GETOSPACE,&ospace);
+ DEBUG("audiosink: (%d bytes buffer)\n", ospace.bytes);
+ write(audiosink->fd,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
+ //gst_clock_set(audiosink->clock, GST_BUFFER_TIMESTAMP(buf));
+ }
+ }
}
}
-
+end:
//g_print("a unref\n");
gst_buffer_unref(buf);
//g_print("a done\n");
GstPad *sinkpad;
- GstClockTime clocktime;
+ //GstClockTime clocktime;
GstClock *clock;
/* soundcard state */
int fd;
//#define DEBUG_ENABLED
//#define STATUS_ENABLED
#ifdef STATUS_ENABLED
-#define STATUS(A) g_print(A)
+#define STATUS(A) DEBUG(A, gst_element_get_name(GST_ELEMENT(queue)))
#else
#define STATUS(A)
#endif
else return NULL;
}
+static void gst_queue_cleanup_buffers(gpointer data, gpointer user_data)
+{
+ DEBUG("queue: %s cleaning buffer %p\n", (gchar *)user_data, data);
+ gst_buffer_unref(GST_BUFFER(data));
+}
+
void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
GstQueue *queue;
gboolean tosignal = FALSE;
name = gst_element_get_name(GST_ELEMENT(queue));
/* we have to lock the queue since we span threads */
+
+ DEBUG("queue: %s adding buffer %p\n", name, buf);
GST_LOCK(queue);
+
+ if (GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLUSH)) {
+ g_list_foreach(queue->queue, gst_queue_cleanup_buffers, name);
+ g_list_free(queue->queue);
+ queue->queue = NULL;
+ queue->level_buffers = 0;
+ }
+
+
DEBUG("queue: %s: chain %d %p\n", name, queue->level_buffers, buf);
if (queue->level_buffers >= queue->max_buffers) {
while (queue->level_buffers >= queue->max_buffers) {
GST_UNLOCK(queue);
g_mutex_lock(queue->fulllock);
- STATUS("O");
+ STATUS("%s: O\n");
g_cond_wait(queue->fullcond,queue->fulllock);
g_mutex_unlock(queue->fulllock);
GST_LOCK(queue);
// queue->tail = g_list_next(queue->tail);
queue->queue = g_list_append(queue->queue,buf);
}
- STATUS("+");
+ STATUS("%s: +\n");
/* if we were empty, but aren't any more, signal a condition */
tosignal = (queue->level_buffers <= 0);
name = gst_element_get_name(GST_ELEMENT(queue));
+ DEBUG("queue: %s push %d\n", name, queue->level_buffers);
/* have to lock for thread-safety */
GST_LOCK(queue);
- DEBUG("queue: %s push %d\n", name, queue->level_buffers);
- if (!queue->level_buffers) {
- while (!queue->level_buffers) {
- GST_UNLOCK(queue);
- g_mutex_lock(queue->emptylock);
- STATUS("U");
- g_cond_wait(queue->emptycond,queue->emptylock);
- g_mutex_unlock(queue->emptylock);
- GST_LOCK(queue);
- }
+ while (!queue->level_buffers) {
+ GST_UNLOCK(queue);
+ g_mutex_lock(queue->emptylock);
+ STATUS("%s: U\n");
+ g_cond_wait(queue->emptycond,queue->emptylock);
+ g_mutex_unlock(queue->emptylock);
+ GST_LOCK(queue);
}
front = queue->queue;
queue->queue = g_list_remove_link(queue->queue,front);
g_list_free(front);
queue->level_buffers--;
- STATUS("-");
+ STATUS("%s: -\n");
tosignal = queue->level_buffers < queue->max_buffers;
GST_UNLOCK(queue);
#define GST_IS_QUEUE(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_QUEUE))
#define GST_IS_QUEUE_CLASS(obj) \
- (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE)))
+ (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
typedef struct _GstQueue GstQueue;
typedef struct _GstQueueClass GstQueueClass;
#ifndef __GST_H__
#define __GST_H__
+#include <unistd.h>
+
#include <gtk/gtk.h>
#include <gst/gstlog.h>
/* debugging */
#ifndef DEBUG
#ifdef DEBUG_ENABLED
-#define DEBUG(format,args...) g_print("DEBUG: " format, ##args)
+#define DEBUG(format, args...) g_print("DEBUG:(%d) " format, getpid() , ##args)
#else
-#define DEBUG(format,args...)
+#define DEBUG(format, args...)
#endif
#endif
the children are, I think. */
// if (GST_STATE_IS_SET(element,GST_STATE_COMPLETE)) {
if (!GST_STATE_IS_SET(bin,GST_STATE_COMPLETE)) {
- g_print("GstBin: adding complete element - ");
+ g_print("GstBin: adding complete element - \n");
gst_bin_change_state_norecurse(GST_ELEMENT(bin),GST_STATE_COMPLETE);
}
// } else {
children = bin->children;
while (children) {
child = GST_ELEMENT(children->data);
-// g_print("gst_bin_change_state setting state on \"%s\"\n",
-// gst_object_get_name(GST_OBJECT(child)));
+ //g_print("gst_bin_change_state setting state on \"%s\"\n",
+ // gst_element_get_name(GST_ELEMENT(child)));
if (!gst_element_set_state(child,state)) {
- g_print("child %p failed to set state 0x%08x\n",child,state);
+ g_print("GstBin: child %p failed to set state 0x%08x\n",child,state);
return FALSE;
}
// g_print("\n");
// g_print("\n");
children = g_list_next(children);
}
-// g_print("<-- \"%s\"\n",gst_object_get_name(GST_OBJECT(bin)));
if (type == GST_TYPE_BIN)
gst_element_change_state(GST_ELEMENT(bin),state);
bin->numentries = 0;
- g_print("attempting to create a plan for bin %p\n",bin);
+ g_print("GstBin: attempting to create a plan for bin %p\n",bin);
/* walk through all the elements to figure out all kinds of things */
elements = GST_BIN(bin)->children;
// have to use cothreads if any elements use loop functions
if (element->loopfunc != NULL) {
if (bin->threadcontext == NULL) {
- g_print("initializing cothread context\n");
+ g_print("GstBin: initializing cothread context\n");
bin->threadcontext = cothread_init();
}
if (element->threadstate == NULL) {
- g_print("creating thread state for element\n");
+ g_print("GstBin: creating thread state for element\n");
element->threadstate = cothread_create(bin->threadcontext);
cothread_setfunc(element->threadstate,gst_element_loopfunc_wrapper,
0,element);
/* we need to find all the entry points into the bin */
if (GST_IS_SRC(element)) {
- g_print("element '%s' is a source entry point for the bin\n",
+ g_print("GstBin: element '%s' is a source entry point for the bin\n",
gst_element_get_name(GST_ELEMENT(element)));
bin->entries = g_list_prepend(bin->entries,element);
bin->numentries++;
/* if it's a connection and it's not ours... */
if (GST_IS_CONNECTION(outside) &&
(gst_object_get_parent(GST_OBJECT(outside)) != GST_OBJECT(bin))) {
- g_print("element '%s' is the external source Connection \
+ g_print("GstBin: element '%s' is the external source Connection \
for internal element '%s'\n",
gst_element_get_name(GST_ELEMENT(outside)),
gst_element_get_name(GST_ELEMENT(element)));
}
elements = g_list_next(elements);
}
- g_print("have %d entries into bin\n",bin->numentries);
+ g_print("GstBin: have %d entries into bin\n",bin->numentries);
}
void gst_bin_iterate_func(GstBin *bin) {
entries = bin->entries;
- g_print("iterating\n");
+ g_print("GstBin: iterating\n");
while (entries) {
entry = GST_ELEMENT(entries->data);
#define GST_BUFFER(buf) \
- ((GstBuffer *)(buf))
-
+ ((GstBuffer *)(buf))
#define GST_BUFFER_FLAGS(buf) \
(GST_BUFFER(buf)->flags)
#include <gstclock.h>
static GstClock *the_system_clock = NULL;
-static int num;
/**
* gst_clock_new:
clock->sinkmutex = g_mutex_new();
clock->lock = g_mutex_new();
g_mutex_lock(clock->sinkmutex);
- num =0;
- clock->locking = TRUE;
+ clock->num = 0;
+ clock->num_locked = 0;
+ clock->locking = FALSE;
return clock;
}
if (GST_IS_SINK(obj)) {
DEBUG("gst_clock: setting registered sink object 0x%p\n", obj);
clock->sinkobjects = g_list_append(clock->sinkobjects, obj);
- num++;
+ clock->num++;
}
}
void gst_clock_set(GstClock *clock, GstClockTime time) {
struct timeval tfnow;
- GstClockTime target, now;
+ GstClockTime now;
+ gettimeofday(&tfnow, (struct timezone *)NULL);
+ now = tfnow.tv_sec*1000000LL+tfnow.tv_usec;
g_mutex_lock(clock->lock);
+ clock->start_time = now - time;
+ g_mutex_unlock(clock->lock);
+ DEBUG("gst_clock: setting clock to %llu %llu %llu\n", time, now, clock->start_time);
+}
+
+GstClockTimeDiff gst_clock_current_diff(GstClock *clock, GstClockTime time)
+{
+ struct timeval tfnow;
+ GstClockTime now;
+
gettimeofday(&tfnow, (struct timezone *)NULL);
- now = tfnow.tv_sec*1000000+tfnow.tv_usec;
- clock->adjust = now - (clock->start_time + time);
- clock->current_time = (clock->start_time + time);
- //DEBUG("gst_clock: setting clock to %llu %llu %lld\n", (guint64)clock->start_time+time, (guint64)now, (gint64)clock->adjust);
+ g_mutex_lock(clock->lock);
+ now = ((guint64)tfnow.tv_sec*1000000LL+tfnow.tv_usec) - (guint64)clock->start_time;
+ //if (clock->locking) now = 0;
g_mutex_unlock(clock->lock);
+
+ //DEBUG("gst_clock: diff with for time %08llu %08lld %08lld %08llu\n", time, now, GST_CLOCK_DIFF(time, now), clock->start_time);
+
+ return GST_CLOCK_DIFF(time, now);
}
void gst_clock_reset(GstClock *clock) {
struct timeval tfnow;
gettimeofday(&tfnow, (struct timezone *)NULL);
- clock->start_time = tfnow.tv_sec*1000000+tfnow.tv_usec;
+ g_mutex_lock(clock->lock);
+ clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec;
clock->current_time = clock->start_time;
clock->adjust = 0LL;
DEBUG("gst_clock: setting start clock %llu\n", clock->start_time);
+ //clock->locking = TRUE;
+ g_mutex_unlock(clock->lock);
}
void gst_clock_wait(GstClock *clock, GstClockTime time, GstObject *obj) {
struct timeval tfnow;
- GstClockTime target, now;
+ GstClockTime now;
GstClockTimeDiff diff;
GList *elements;
- DEBUG("gst_clock: requesting clock object 0x%p\n", obj);
- g_mutex_lock(clock->lock);
- elements = clock->sinkobjects;
- while (elements && clock->locking) {
- if (elements->data == obj) {
- DEBUG("gst_clock: registered sink object 0x%p\n", obj);
- num--;
- if (num) {
- DEBUG("gst_clock: 0x%p locked\n", obj);
- g_mutex_unlock(clock->lock);
- g_mutex_lock(clock->sinkmutex);
- g_mutex_lock(clock->lock);
- clock->locking = FALSE;
- }
- else {
- gst_clock_reset(clock);
- DEBUG("gst_clock: unlock all %p\n", obj);
- g_mutex_unlock(clock->sinkmutex);
- clock->locking = FALSE;
- }
- break;
- }
- elements = g_list_next(elements);
- }
+ //DEBUG("gst_clock: requesting clock object 0x%p %08llu %08llu\n", obj, time, clock->current_time);
- target = clock->start_time + time;
gettimeofday(&tfnow, (struct timezone *)NULL);
- now = tfnow.tv_sec*1000000+tfnow.tv_usec + clock->adjust;
+ g_mutex_lock(clock->lock);
+ now = tfnow.tv_sec*1000000LL+tfnow.tv_usec - clock->start_time;
//now = clock->current_time + clock->adjust;
- //DEBUG("gst_clock: 0x%p waiting for time %llu %llu\n", obj, time, target);
-
- diff = GST_CLOCK_DIFF(target, now);
+ diff = GST_CLOCK_DIFF(time, now);
// if we are not behind wait a bit
+ DEBUG("gst_clock: %s waiting for time %08llu %08llu %08lld\n", gst_element_get_name(GST_ELEMENT(obj)), time, now, diff);
- if (diff > 1000 ) {
- tfnow.tv_usec = diff % 1000000;
+ g_mutex_unlock(clock->lock);
+ if (diff > 10000 ) {
+ tfnow.tv_usec = (diff % 1000000);
tfnow.tv_sec = diff / 1000000;
// FIXME, this piece of code does not work with egcs optimisations on, had to use the following line
- if (tfnow.tv_sec) fprintf(stderr, "gst_clock: waiting %u %llu %llu %llu seconds\n", (int)tfnow.tv_sec, now, diff, target);
- g_mutex_unlock(clock->lock);
+ if (!tfnow.tv_sec) {
+ select(0, NULL, NULL, NULL, &tfnow);
+ }
+ else fprintf(stderr, "gst_clock: waiting %u %llu %llu %llu seconds\n", (int)tfnow.tv_sec, now, diff, time);
//DEBUG("gst_clock: 0x%p waiting for time %llu %llu %lld %llu\n", obj, time, target, diff, now);
- select(0, NULL, NULL, NULL, &tfnow);
- //DEBUG("gst_clock: 0x%p waiting done time %llu %llu\n", obj, time, target);
- g_mutex_lock(clock->lock);
+ //DEBUG("waiting %d.%08d\n",tfnow.tv_sec, tfnow.tv_usec);
+ //DEBUG("gst_clock: 0x%p waiting done time %llu \n", obj, time);
}
+ DEBUG("gst_clock: %s waiting for time %08llu %08llu %08lld done \n", gst_element_get_name(GST_ELEMENT(obj)), time, now, diff);
// clock->current_time = clock->start_time + time;
- g_mutex_unlock(clock->lock);
//gst_clock_set(clock, time);
}
GstClockTimeDiff adjust;
gboolean locking;
GList *sinkobjects;
+ gint num, num_locked;
GMutex *sinkmutex;
GMutex *lock;
};
void gst_clock_set(GstClock *clock, GstClockTime time);
void gst_clock_reset(GstClock *clock);
void gst_clock_wait(GstClock *clock, GstClockTime time, GstObject *obj);
+GstClockTimeDiff gst_clock_current_diff(GstClock *clock, GstClockTime time);
#ifdef __cplusplus
}
static void gst_element_init(GstElement *element);
static void gst_element_real_destroy(GtkObject *object);
-
static GstObjectClass *parent_class = NULL;
static guint gst_element_signals[LAST_SIGNAL] = { 0 };
* condition. It results in the "error" signal.
*/
void gst_element_error(GstElement *element,gchar *error) {
- g_error("error in element '%s': %s\n",element->name,error);
+ g_error("GstElement: error in element '%s': %s\n",element->name,error);
gtk_signal_emit(GTK_OBJECT(element),gst_element_signals[ERROR],error);
}
// element->name,state);
/* deal with the inverted state */
-// g_print("changing element state, was %08lx",GST_STATE(element));
+ //g_print("changing element state, was %08lx\n",GST_STATE(element));
if (state & GST_STATE_MAX)
GST_STATE_UNSET(element,~state);
else
break;
case GTK_TYPE_DOUBLE:
xmlNewChild(arg,NULL,"value",
- g_strdup_printf("%lf",GTK_VALUE_DOUBLE(args[i])));
+ g_strdup_printf("%g",GTK_VALUE_DOUBLE(args[i])));
break;
case GTK_TYPE_STRING:
xmlNewChild(arg,NULL,"value",GTK_VALUE_STRING(args[i]));
#define GST_STATE_IS_SET(obj,flag) (GST_STATE (obj) & (flag))
#define GST_STATE_SET(obj,flag) \
G_STMT_START{ (GST_STATE (obj) |= (flag)); \
-gst_info("set '%s' state %d\n",gst_element_get_name(obj),flag); \
+gst_info("GstElement: set '%s' state %d\n",gst_element_get_name(obj),flag); \
}G_STMT_END
#define GST_STATE_UNSET(obj,flag) \
G_STMT_START{ (GST_STATE (obj) &= ~(flag)); \
-gst_info("unset '%s' state %d\n",gst_element_get_name(obj),flag); \
+gst_info("GstElement: unset '%s' state %d\n",gst_element_get_name(obj),flag); \
}G_STMT_END
*/
+//#define DEBUG_ENABLED
+#include <gst/gst.h>
#include <gst/gstpad.h>
#include <gst/gstelement.h>
#include <gst/gsttype.h>
pad->peer = NULL;
pad->chain = NULL;
pad->pull = NULL;
+ pad->qos = NULL;
pad->parent = NULL;
pad->ghostparents = NULL;
}
pad->chain = chain;
}
+void gst_pad_set_qos_function(GstPad *pad,GstPadQoSFunction qos) {
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+
+ pad->qos = qos;
+}
+
void gst_pad_push(GstPad *pad,GstBuffer *buffer) {
g_return_if_fail(pad != NULL);
g_return_if_fail(GST_IS_PAD(pad));
// else we're likely going to have to coroutine it
else {
pad->peer->bufpen = buffer;
- g_print("would switch to a coroutine here...\n");
+ g_print("GstPad: would switch to a coroutine here...\n");
if (!GST_IS_ELEMENT(pad->peer->parent))
- g_print("eek, this isn't an element!\n");
+ g_print("GstPad: eek, this isn't an element!\n");
if (GST_ELEMENT(pad->peer->parent)->threadstate != NULL)
cothread_switch(GST_ELEMENT(pad->peer->parent)->threadstate);
}
g_return_val_if_fail(pad != NULL, NULL);
g_return_val_if_fail(GST_IS_PAD(pad), NULL);
- // if the pull function exists for the pad, call it directly
- if (pad->pull) {
- return (pad->pull)(pad->peer);
+ // if the pull function exists for the pad, call it directly
+ if (pad->pull) {
+ return (pad->pull)(pad->peer);
// else we're likely going to have to coroutine it
- } else if (pad->bufpen == NULL) {
- g_print("no buffer available, will have to do something about it\n");
+ } else if (pad->bufpen == NULL) {
+ g_print("GstPad: no buffer available, will have to do something about it\n");
peerparent = GST_ELEMENT(pad->peer->parent);
// if they're a cothread too, we can just switch to them
if (peerparent->threadstate != NULL) {
// otherwise we have to switch to the main thread
} else {
state = cothread_main(GST_ELEMENT(pad->parent)->threadstate->ctx);
- g_print("switching to supposed 0th thread at %p\n",state);
+ g_print("GstPad: switching to supposed 0th thread at %p\n",state);
cothread_switch(state);
}
} else {
- g_print("buffer available, pulling\n");
+ g_print("GstPad: buffer available, pulling\n");
buf = pad->bufpen;
pad->bufpen = NULL;
return buf;
(pad->chain)(pad,pad->bufpen);
}
+/**
+ * gst_pad_handle_qos:
+ * @element: element to change state of
+ * @state: new element state
+ *
+ */
+void gst_pad_handle_qos(GstPad *pad,
+ glong qos_message)
+{
+ GstElement *element;
+ GList *pads;
+ GstPad *target_pad;
+
+ DEBUG("gst_pad_handle_qos(\"%s\",%08ld)\n", GST_ELEMENT(pad->parent)->name,qos_message);
+
+ if (pad->qos) {
+ (pad->qos)(pad,qos_message);
+ }
+ else {
+ element = GST_ELEMENT(pad->peer->parent);
+
+ pads = element->pads;
+ DEBUG("gst_pad_handle_qos recurse(\"%s\",%08ld)\n", element->name,qos_message);
+ while (pads) {
+ target_pad = GST_PAD(pads->data);
+ if (target_pad->direction == GST_PAD_SINK) {
+ gst_pad_handle_qos(target_pad, qos_message);
+ }
+ pads = g_list_next(pads);
+ }
+ }
+
+ return;
+}
+
void gst_pad_disconnect(GstPad *srcpad,GstPad *sinkpad) {
/* generic checks */
typedef void (*GstPadChainFunction) (GstPad *pad,GstBuffer *buf);
typedef GstBuffer *(*GstPadPullFunction) (GstPad *pad);
typedef void (*GstPadPushFunction) (GstPad *pad);
+typedef void (*GstPadQoSFunction) (GstPad *pad, glong qos_message);
typedef enum {
GST_PAD_UNKNOWN,
GstPadChainFunction chain;
GstPadPullFunction pull;
+ GstPadQoSFunction qos;
GstObject *parent;
GList *ghostparents;
GstPadDirection gst_pad_get_direction(GstPad *pad);
void gst_pad_set_chain_function(GstPad *pad,GstPadChainFunction chain);
void gst_pad_set_pull_function(GstPad *pad, GstPadPullFunction pull);
+void gst_pad_set_qos_function(GstPad *pad, GstPadQoSFunction qos);
guint16 gst_pad_get_type_id(GstPad *pad);
void gst_pad_set_type_id(GstPad *pad,guint16 id);
void gst_pad_push(GstPad *pad,GstBuffer *buffer);
GstBuffer *gst_pad_pull(GstPad *pad);
+void gst_pad_handle_qos(GstPad *pad, glong qos_message);
xmlNodePtr gst_pad_save_thyself(GstPad *pad,xmlNodePtr parent);
}
static void gst_pipeline_prepare(GstPipeline *pipeline) {
- g_print("preparing pipeline for playing\n");
+ g_print("GstPipeline: preparing pipeline \"%s\" for playing\n", gst_element_get_name(GST_ELEMENT(pipeline)));
}
switch (state) {
case GST_STATE_RUNNING:
/* we need to set up internal state */
- g_print("preparing pipeline \"%s\" for iterations:\n",
+ g_print("GstPipeline: preparing pipeline \"%s\" for iterations:\n",
gst_element_get_name(GST_ELEMENT(element)));
gst_pipeline_prepare(pipeline);
break;
case ~GST_STATE_RUNNING:
/* tear down the internal state */
- g_print("tearing down pipelines's iteration state\n");
+ g_print("GstPipeline: tearing down pipelines's \"%s\" iteration state\n",
+ gst_element_get_name(GST_ELEMENT(element)));
break;
default:
break;
* Boston, MA 02111-1307, USA.
*/
+#include <gst/gst.h>
#include <gst/gstthread.h>
GstElementDetails gst_thread_details = {
switch(id) {
case ARG_CREATE_THREAD:
if (GTK_VALUE_BOOL(*arg)) {
- gst_info("turning ON the creation of the thread\n");
+ gst_info("gstthread: turning ON the creation of the thread\n");
GST_FLAG_SET(object,GST_THREAD_CREATE);
- gst_info("flags are 0x%08x\n",GST_FLAGS(object));
+ gst_info("gstthread: flags are 0x%08x\n",GST_FLAGS(object));
} else {
- gst_info("turning OFF the creation of the thread\n");
+ gst_info("gstthread: turning OFF the creation of the thread\n");
GST_FLAG_UNSET(object,GST_THREAD_CREATE);
- gst_info("flags are 0x%08x\n",GST_FLAGS(object));
+ gst_info("gstthread: flags are 0x%08x\n",GST_FLAGS(object));
}
break;
default:
while (elements) {
element = GST_ELEMENT(elements->data);
if (GST_IS_SRC(element)) {
- gst_info("element \"%s\" is a source entry point for the thread\n",
+ gst_info("gstthread: element \"%s\" is a source entry point for the thread\n",
gst_element_get_name(GST_ELEMENT(element)));
thread->entries = g_list_prepend(thread->entries,element);
thread->numentries++;
/* if it's a connection and it's not ours... */
if (GST_IS_CONNECTION(outside) &&
(gst_object_get_parent(GST_OBJECT(outside)) != GST_OBJECT(thread))) {
- gst_info("element \"%s\" is the external source Connection \
+ gst_info("gstthread: element \"%s\" is the external source Connection \
for internal element \"%s\"\n",
gst_element_get_name(GST_ELEMENT(outside)),
gst_element_get_name(GST_ELEMENT(element)));
}
elements = g_list_next(elements);
}
- gst_info("have %d entries into thread\n",thread->numentries);
+ gst_info("gstthread: have %d entries into thread\n",thread->numentries);
}
case GST_STATE_RUNNING:
if (!stateset) return FALSE;
/* we want to prepare our internal state for doing the iterations */
- gst_info("preparing thread \"%s\" for iterations:\n",
+ gst_info("gstthread: preparing thread \"%s\" for iterations:\n",
gst_element_get_name(GST_ELEMENT(element)));
gst_thread_prepare(thread);
if (thread->numentries == 0)
/* set the state to idle */
GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
/* create the thread if that's what we're supposed to do */
- gst_info("flags are 0x%08x\n",GST_FLAGS(thread));
+ gst_info("gstthread: flags are 0x%08x\n",GST_FLAGS(thread));
if (GST_FLAG_IS_SET(thread,GST_THREAD_CREATE)) {
- gst_info("starting thread \"%s\"\n",
+ gst_info("gstthread: starting thread \"%s\"\n",
gst_element_get_name(GST_ELEMENT(element)));
pthread_create(&thread->thread_id,NULL,
gst_thread_main_loop,thread);
} else {
- gst_info("NOT starting thread \"%s\"\n",
+ gst_info("gstthread: NOT starting thread \"%s\"\n",
gst_element_get_name(GST_ELEMENT(element)));
}
return TRUE;
gst_thread_signal_thread(thread);
pthread_join(thread->thread_id,0);
/* tear down the internal state */
- gst_info("tearing down thread's iteration state\n");
+ gst_info("gstthread: tearing down thread's iteration state\n");
/* FIXME do stuff */
break;
case GST_STATE_PLAYING:
if (!stateset) return FALSE;
- gst_info("starting thread \"%s\"\n",
+ gst_info("gstthread: starting thread \"%s\"\n",
gst_element_get_name(GST_ELEMENT(element)));
GST_FLAG_SET(thread,GST_THREAD_STATE_SPINNING);
gst_thread_signal_thread(thread);
return TRUE;
break;
case ~GST_STATE_PLAYING:
- gst_info("stopping thread \"%s\"\n",
+ gst_info("gstthread: stopping thread \"%s\"\n",
gst_element_get_name(GST_ELEMENT(element)));
GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
gst_thread_signal_thread(thread);
void *gst_thread_main_loop(void *arg) {
GstThread *thread = GST_THREAD(arg);
- gst_info("HI, IN MAIN THREAD LOOP!\n");
+ gst_info("gstthread: thread \"%s\" is running with PID %d\n",
+ gst_element_get_name(GST_ELEMENT(thread)), getpid());
while(!GST_FLAG_IS_SET(thread,GST_THREAD_STATE_REAPING)) {
if (GST_FLAG_IS_SET(thread,GST_THREAD_STATE_SPINNING))
GST_FLAG_UNSET(thread,GST_THREAD_STATE_REAPING);
- gst_info("GOODBYE, LEAVING MAIN THREAD LOOP!\n");
+ gst_info("gstthread: thread \"%s\" is stopped\n",
+ gst_element_get_name(GST_ELEMENT(thread)));
return NULL;
}
entries = thread->entries;
+ DEBUG("gstthread: %s: thread iterate\n", gst_element_get_name(GST_ELEMENT(thread)));
+
while (entries) {
entry = GST_ELEMENT(entries->data);
if (GST_IS_SRC(entry))
g_assert_not_reached();
entries = g_list_next(entries);
}
+ DEBUG("gstthread: %s: thread iterate done\n", gst_element_get_name(GST_ELEMENT(thread)));
//g_print(",");
}
on_play2_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
+ update_buttons(0);
+ change_state(GSTPLAY_PLAYING);
}
on_pause1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
+ update_buttons(1);
+ change_state(GSTPLAY_PAUSE);
}
on_stop1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
+ update_buttons(2);
+ change_state(GSTPLAY_STOPPED);
}
# include <config.h>
#endif
+//#define DEBUG_ENABLED
+
+#include <gst/gstclock.h>
+
#include "gstplay.h"
#include "interface.h"
#include "codecs.h"
+#define MUTEX_STATUS() (g_mutex_trylock(gdk_threads_mutex)? g_mutex_unlock(gdk_threads_mutex), "was not locked" : "was locked")
+
+
+#define BUFFER 4
+
extern gboolean _gst_plugin_spew;
gboolean idle_func(gpointer data);
-GstElement *show, *audio_play;
+GstElement *show, *video_render_queue;
+GstElement *audio_play, *audio_render_queue;
GstElement *src;
GstPipeline *pipeline;
GstElement *parse = NULL;
guint mux_rate;
static int prev_time = -1;
+ DEBUG("gstplay: frame displayed %s\n", MUTEX_STATUS());
+
mux_rate = gst_util_get_int_arg(GTK_OBJECT(parse),"mux_rate");
size = gst_util_get_int_arg(GTK_OBJECT(src),"size");
time = (size*8)/mux_rate;
picture_shown = TRUE;
prev_time = frame_time;
+ DEBUG("gstplay: frame displayed end %s\n", MUTEX_STATUS());
}
gboolean idle_func(gpointer data) {
+ DEBUG("idle start %s\n",MUTEX_STATUS());
gst_src_push(GST_SRC(data));
+ DEBUG("idle stop %s\n",MUTEX_STATUS());
return TRUE;
}
void show_next_picture() {
picture_shown = FALSE;
+ DEBUG("gstplay: next picture %s\n", MUTEX_STATUS());
while (!picture_shown) {
+ gdk_threads_leave();
gst_src_push(GST_SRC(src));
- gtk_main_iteration_do(FALSE);
+ gdk_threads_enter();
}
+ DEBUG("gstplay: next found %s\n", MUTEX_STATUS());
}
void mute_audio(gboolean mute) {
gtk_object_set(GTK_OBJECT(audio_play),"mute",mute,NULL);
}
+void gstplay_parse_state_changed(GstElement *element, gint state, gpointer data)
+{
+ printf("gstplay: element \"%s\" state changed %d\n", gst_element_get_name(element), state);
+
+ if (state == GST_STATE_COMPLETE) {
+ g_print("gstplay: setting to PLAYING state\n");
+ gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
+ gst_clock_reset(gst_clock_get_system());
+ g_print("gstplay: PLAYING\n");
+ }
+}
+
void change_state(GstPlayState new_state) {
if (new_state == state) return;
gst_element_get_pad(GST_ELEMENT(sink),"sink"));
if (strstr(gsttype->mime, "mpeg1-system")) {
- parse = gst_elementfactory_make("mpeg1parse","parse");
+ parse = gst_elementfactory_make("mpeg1parse","mpeg1_system_parse");
gtk_signal_connect(GTK_OBJECT(parse),"new_pad",
GTK_SIGNAL_FUNC(mpeg1_new_pad_created),pipeline);
}
else if (strstr(gsttype->mime, "mpeg2-system")) {
- parse = gst_elementfactory_make("mpeg2parse","parse");
+ parse = gst_elementfactory_make("mpeg2parse","mpeg2_system_parse");
gtk_signal_connect(GTK_OBJECT(parse),"new_pad",
GTK_SIGNAL_FUNC(mpeg2_new_pad_created),pipeline);
}
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
+ gtk_signal_connect(GTK_OBJECT(parse),"state_change",
+ GTK_SIGNAL_FUNC(gstplay_parse_state_changed),pipeline);
}
gtk_object_set(GTK_OBJECT(src),"offset",0,NULL);
{
GtkWidget *window1;
GstElement *typefind;
+ GstElement *video_render_thread;
+ GstElement *audio_render_thread;
bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR);
textdomain (PACKAGE);
+ g_thread_init(NULL);
gtk_init(&argc,&argv);
gnome_init ("gstreamer", VERSION, argc, argv);
gst_init(&argc,&argv);
gst_plugin_load("mpeg2parse");
gst_plugin_load("mp1videoparse");
gst_plugin_load("mp3parse");
- //gst_plugin_load("parsewav");
- //gst_plugin_load("parseavi");
+ gst_plugin_load("parsewav");
+ gst_plugin_load("parseavi");
gst_plugin_load("videosink");
g_snprintf(statusline, 200, "seeking");
+ pipeline = gst_pipeline_new("main_pipeline");
+ g_return_val_if_fail(pipeline != NULL, -1);
+
+ video_render_thread = gst_thread_new("video_render_thread");
+ g_return_val_if_fail(video_render_thread != NULL, -1);
show = gst_elementfactory_make("videosink","show");
g_return_val_if_fail(show != NULL, -1);
+ gtk_object_set(GTK_OBJECT(show),"xv_enabled",FALSE,NULL);
window1 = create_window1 (gst_util_get_widget_arg(GTK_OBJECT(show),"widget"));
gtk_widget_show (window1);
gtk_signal_connect(GTK_OBJECT(show),"frame_displayed",
GTK_SIGNAL_FUNC(frame_displayed),NULL);
+ gst_bin_add(GST_BIN(video_render_thread),GST_ELEMENT(show));
+ gst_element_add_ghost_pad(GST_ELEMENT(video_render_thread),
+ gst_element_get_pad(show,"sink"));
+
+ video_render_queue = gst_elementfactory_make("queue","video_render_queue");
+ gtk_object_set(GTK_OBJECT(video_render_queue),"max_level",BUFFER,NULL);
+ gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(video_render_queue));
+ gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(video_render_thread));
+ gst_pad_connect(gst_element_get_pad(video_render_queue,"src"),
+ gst_element_get_pad(video_render_thread,"sink"));
+ gtk_object_set(GTK_OBJECT(video_render_thread),"create_thread",TRUE,NULL);
+
+ audio_render_thread = gst_thread_new("audio_render_thread");
+ g_return_val_if_fail(audio_render_thread != NULL, -1);
audio_play = gst_elementfactory_make("audiosink","play_audio");
+ gst_bin_add(GST_BIN(audio_render_thread),GST_ELEMENT(audio_play));
+ gst_element_add_ghost_pad(GST_ELEMENT(audio_render_thread),
+ gst_element_get_pad(audio_play,"sink"));
+
+ audio_render_queue = gst_elementfactory_make("queue","audio_render_queue");
+ gtk_object_set(GTK_OBJECT(audio_render_queue),"max_level",BUFFER,NULL);
+ gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(audio_render_queue));
+ gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(audio_render_thread));
+ gst_pad_connect(gst_element_get_pad(audio_render_queue,"src"),
+ gst_element_get_pad(audio_render_thread,"sink"));
+ gtk_object_set(GTK_OBJECT(audio_render_thread),"create_thread",TRUE,NULL);
- pipeline = gst_pipeline_new("pipeline");
- g_return_val_if_fail(pipeline != NULL, -1);
- src = gst_elementfactory_make("disksrc","src");
+ src = gst_elementfactory_make("disksrc","disk_src");
g_return_val_if_fail(src != NULL, -1);
- gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
g_print("should be using file '%s'\n",argv[1]);
+ gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
gtk_window_set_title (GTK_WINDOW (window1), g_strdup_printf("GStreamer Media player - %s", argv[1]));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(typefind,"sink"));
+ g_print("setting to PREROLL state\n");
+ gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PREROLL);
g_print("setting to RUNNING state\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
change_state(GSTPLAY_PLAYING);
+ gdk_threads_enter();
gtk_main();
+ gdk_threads_leave();
return 0;
}
-#define BUFFER 15
+#define BUFFER 20
#define VIDEO_DECODER "mpeg_play"
#ifdef HAVE_CONFIG_H
extern gboolean _gst_plugin_spew;
-extern GstElement *show;
-extern GstElement *audio_play;
+extern GstElement *video_render_queue;
+extern GstElement *audio_render_queue;
void mpeg1_new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline)
{
// connect to audio pad
//if (0) {
- if (strncmp(gst_pad_get_name(pad), "audio_", 6) == 0 && audio_play) {
+ if (strncmp(gst_pad_get_name(pad), "audio_", 6) == 0 && audio_render_queue) {
gst_plugin_load("mp3parse");
gst_plugin_load("mpg123");
// construct internal pipeline elements
g_return_if_fail(audio_thread != NULL);
gst_bin_add(GST_BIN(audio_thread),GST_ELEMENT(parse_audio));
gst_bin_add(GST_BIN(audio_thread),GST_ELEMENT(decode));
- gst_bin_add(GST_BIN(audio_thread),GST_ELEMENT(audio_play));
// set up pad connections
gst_element_add_ghost_pad(GST_ELEMENT(audio_thread),
gst_pad_connect(gst_element_get_pad(parse_audio,"src"),
gst_element_get_pad(decode,"sink"));
gst_pad_connect(gst_element_get_pad(decode,"src"),
- gst_element_get_pad(audio_play,"sink"));
+ gst_element_get_pad(audio_render_queue,"sink"));
// construct queue and connect everything in the main pipelie
audio_queue = gst_elementfactory_make("queue","audio_queue");
gtk_object_set(GTK_OBJECT(audio_thread),"create_thread",TRUE,NULL);
g_print("setting to RUNNING state\n");
gst_element_set_state(GST_ELEMENT(audio_thread),GST_STATE_RUNNING);
- g_print("setting to PLAYING state\n");
- gst_element_set_state(GST_ELEMENT(audio_thread),GST_STATE_PLAYING);
+ //g_print("setting to PLAYING state\n");
+ //gst_element_set_state(GST_ELEMENT(audio_thread),GST_STATE_PLAYING);
} else if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
//} else if (0) {
- mpeg1_setup_video_thread(pad, show, pipeline);
+ mpeg1_setup_video_thread(pad, video_render_queue, pipeline);
}
}
-void mpeg1_setup_video_thread(GstPad *pad, GstElement *show, GstElement *pipeline)
+void mpeg1_setup_video_thread(GstPad *pad, GstElement *video_render_queue, GstElement *pipeline)
{
GstElement *parse_video, *decode_video;
GstElement *video_queue;
g_return_if_fail(video_thread != NULL);
gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(parse_video));
gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(decode_video));
- gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(show));
// set up pad connections
gst_element_add_ghost_pad(GST_ELEMENT(video_thread),
gst_pad_connect(gst_element_get_pad(parse_video,"src"),
gst_element_get_pad(decode_video,"sink"));
gst_pad_connect(gst_element_get_pad(decode_video,"src"),
- gst_element_get_pad(show,"sink"));
+ gst_element_get_pad(video_render_queue,"sink"));
// construct queue and connect everything in the main pipeline
video_queue = gst_elementfactory_make("queue","video_queue");
gtk_object_set(GTK_OBJECT(video_thread),"create_thread",TRUE,NULL);
g_print("setting to RUNNING state\n");
gst_element_set_state(GST_ELEMENT(video_thread),GST_STATE_RUNNING);
- g_print("setting to PLAYING state\n");
- gst_element_set_state(GST_ELEMENT(video_thread),GST_STATE_PLAYING);
-
- g_print("\n");
+ //g_print("setting to PLAYING state\n");
+ //gst_element_set_state(GST_ELEMENT(video_thread),GST_STATE_PLAYING);
}
#define mmx_m2r(op, mem, reg) \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
- : "X" (mem))
+ : "m" (mem))
#define mmx_r2m(op, reg, mem) \
__asm__ __volatile__ (#op " %%" #reg ", %0" \
- : "=X" (mem) \
+ : "=m" (mem) \
: /* nothing */ )
#define mmx_r2r(op, regs, regd) \
__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
#op " %1, %%mm0\n\t" \
"movq %%mm0, %0" \
- : "=X" (memd) \
- : "X" (mems))
+ : "=m" (memd) \
+ : "m" (mems))
#endif
audiosink->fd = -1;
audiosink->clock = gst_clock_get_system();
gst_clock_register(audiosink->clock, GST_OBJECT(audiosink));
- audiosink->clocktime = 0LL;
+ //audiosink->clocktime = 0LL;
- gst_element_set_state(GST_ELEMENT(audiosink),GST_STATE_COMPLETE);
}
void gst_audiosink_sync_parms(GstAudioSink *audiosink) {
audiosink->frequency,audiosink->format,
(audiosink->channels == 2) ? "stereo" : "mono",ospace.bytes, frag);
-
}
GstElement *gst_audiosink_new(gchar *name) {
GstElement *audiosink = GST_ELEMENT(gtk_type_new(GST_TYPE_AUDIOSINK));
gst_element_set_name(GST_ELEMENT(audiosink),name);
+ gst_element_set_state(GST_ELEMENT(audiosink),GST_STATE_COMPLETE);
return audiosink;
}
void gst_audiosink_chain(GstPad *pad,GstBuffer *buf) {
GstAudioSink *audiosink;
MetaAudioRaw *meta;
- count_info info;
+ gboolean in_flush;
+ audio_buf_info ospace;
g_return_if_fail(pad != NULL);
g_return_if_fail(GST_IS_PAD(pad));
audiosink = GST_AUDIOSINK(pad->parent);
// g_return_if_fail(GST_FLAG_IS_SET(audiosink,GST_STATE_RUNNING));
+ if (in_flush = GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLUSH)) {
+ DEBUG("audiosink: flush\n");
+ ioctl(audiosink->fd,SNDCTL_DSP_RESET,0);
+ }
+
+
meta = (MetaAudioRaw *)gst_buffer_get_first_meta(buf);
if (meta != NULL) {
if ((meta->format != audiosink->format) ||
gst_trace_add_entry(NULL,0,buf,"audiosink: writing to soundcard");
//g_print("audiosink: writing to soundcard\n");
if (audiosink->fd > 2) {
- if (audiosink->clocktime == 0LL)
- gst_clock_wait(audiosink->clock, audiosink->clocktime, GST_OBJECT(audiosink));
- ioctl(audiosink->fd,SNDCTL_DSP_GETOPTR,&info);
- audiosink->clocktime = (info.bytes*1000000LL)/(audiosink->frequency*audiosink->channels);
- //g_print("audiosink: bytes sent %d time %llu\n", info.bytes, audiosink->clocktime);
- gst_clock_set(audiosink->clock, audiosink->clocktime);
- if (!audiosink->mute)
- write(audiosink->fd,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
- //audiosink->clocktime += (1000000LL*GST_BUFFER_SIZE(buf)/(audiosink->channels*
-// (audiosink->format/8)*(audiosink->frequency)));
- //g_print("audiosink: writing to soundcard ok\n");
+ if (!audiosink->mute) {
+ if (gst_clock_current_diff(audiosink->clock, GST_BUFFER_TIMESTAMP(buf)) > 500000) {
+ }
+ else {
+ gst_clock_wait(audiosink->clock, GST_BUFFER_TIMESTAMP(buf), GST_OBJECT(audiosink));
+ ioctl(audiosink->fd,SNDCTL_DSP_GETOSPACE,&ospace);
+ DEBUG("audiosink: (%d bytes buffer)\n", ospace.bytes);
+ write(audiosink->fd,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
+ //gst_clock_set(audiosink->clock, GST_BUFFER_TIMESTAMP(buf));
+ }
+ }
}
}
-
+end:
//g_print("a unref\n");
gst_buffer_unref(buf);
//g_print("a done\n");
GstPad *sinkpad;
- GstClockTime clocktime;
+ //GstClockTime clocktime;
GstClock *clock;
/* soundcard state */
int fd;
//#define DEBUG_ENABLED
//#define STATUS_ENABLED
#ifdef STATUS_ENABLED
-#define STATUS(A) g_print(A)
+#define STATUS(A) DEBUG(A, gst_element_get_name(GST_ELEMENT(queue)))
#else
#define STATUS(A)
#endif
else return NULL;
}
+static void gst_queue_cleanup_buffers(gpointer data, gpointer user_data)
+{
+ DEBUG("queue: %s cleaning buffer %p\n", (gchar *)user_data, data);
+ gst_buffer_unref(GST_BUFFER(data));
+}
+
void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
GstQueue *queue;
gboolean tosignal = FALSE;
name = gst_element_get_name(GST_ELEMENT(queue));
/* we have to lock the queue since we span threads */
+
+ DEBUG("queue: %s adding buffer %p\n", name, buf);
GST_LOCK(queue);
+
+ if (GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLUSH)) {
+ g_list_foreach(queue->queue, gst_queue_cleanup_buffers, name);
+ g_list_free(queue->queue);
+ queue->queue = NULL;
+ queue->level_buffers = 0;
+ }
+
+
DEBUG("queue: %s: chain %d %p\n", name, queue->level_buffers, buf);
if (queue->level_buffers >= queue->max_buffers) {
while (queue->level_buffers >= queue->max_buffers) {
GST_UNLOCK(queue);
g_mutex_lock(queue->fulllock);
- STATUS("O");
+ STATUS("%s: O\n");
g_cond_wait(queue->fullcond,queue->fulllock);
g_mutex_unlock(queue->fulllock);
GST_LOCK(queue);
// queue->tail = g_list_next(queue->tail);
queue->queue = g_list_append(queue->queue,buf);
}
- STATUS("+");
+ STATUS("%s: +\n");
/* if we were empty, but aren't any more, signal a condition */
tosignal = (queue->level_buffers <= 0);
name = gst_element_get_name(GST_ELEMENT(queue));
+ DEBUG("queue: %s push %d\n", name, queue->level_buffers);
/* have to lock for thread-safety */
GST_LOCK(queue);
- DEBUG("queue: %s push %d\n", name, queue->level_buffers);
- if (!queue->level_buffers) {
- while (!queue->level_buffers) {
- GST_UNLOCK(queue);
- g_mutex_lock(queue->emptylock);
- STATUS("U");
- g_cond_wait(queue->emptycond,queue->emptylock);
- g_mutex_unlock(queue->emptylock);
- GST_LOCK(queue);
- }
+ while (!queue->level_buffers) {
+ GST_UNLOCK(queue);
+ g_mutex_lock(queue->emptylock);
+ STATUS("%s: U\n");
+ g_cond_wait(queue->emptycond,queue->emptylock);
+ g_mutex_unlock(queue->emptylock);
+ GST_LOCK(queue);
}
front = queue->queue;
queue->queue = g_list_remove_link(queue->queue,front);
g_list_free(front);
queue->level_buffers--;
- STATUS("-");
+ STATUS("%s: -\n");
tosignal = queue->level_buffers < queue->max_buffers;
GST_UNLOCK(queue);
#define GST_IS_QUEUE(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_QUEUE))
#define GST_IS_QUEUE_CLASS(obj) \
- (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE)))
+ (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
typedef struct _GstQueue GstQueue;
typedef struct _GstQueueClass GstQueueClass;