This is the audio/video sync release.
authorWim Taymans <wim.taymans@gmail.com>
Wed, 12 Jul 2000 22:52:42 +0000 (22:52 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Wed, 12 Jul 2000 22:52:42 +0000 (22:52 +0000)
Original commit message from CVS:
This is the audio/video sync release.
Changed the mpegvideoparser to parse complete pictures. Added the PTS
timestamps to the pictures.
Added PTS timestamps to the MPEG audio frames.
Made the clock a littlebit better.
Gstplay now uses two more threads one for video, one for audio playback.
Added the first QoS callbacks for the pads.
hopefully fix an mmx compilation problem.

25 files changed:
configure.in
docs/random/states.new [new file with mode: 0644]
gst/elements/gstaudiosink.c
gst/elements/gstaudiosink.h
gst/elements/gstqueue.c
gst/elements/gstqueue.h
gst/gst.h
gst/gstbin.c
gst/gstbuffer.h
gst/gstclock.c
gst/gstclock.h
gst/gstelement.c
gst/gstelement.h
gst/gstpad.c
gst/gstpad.h
gst/gstpipeline.c
gst/gstthread.c
gstplay/callbacks.c
gstplay/gstplay.c
gstplay/mpeg1.c
include/mmx.h
plugins/elements/gstaudiosink.c
plugins/elements/gstaudiosink.h
plugins/elements/gstqueue.c
plugins/elements/gstqueue.h

index d3835c4..a27c3e8 100644 (file)
@@ -101,19 +101,6 @@ AC_CHECK_LIB(ghttp, ghttp_request_new,
 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)
@@ -155,6 +142,19 @@ HAVE_LIBMMX="no"
 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) 
diff --git a/docs/random/states.new b/docs/random/states.new
new file mode 100644 (file)
index 0000000..1df4e72
--- /dev/null
@@ -0,0 +1,79 @@
+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.
index b136419..6c0a249 100644 (file)
@@ -147,9 +147,8 @@ static void gst_audiosink_init(GstAudioSink *audiosink) {
   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) {
@@ -173,19 +172,20 @@ 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));
@@ -197,6 +197,12 @@ void gst_audiosink_chain(GstPad *pad,GstBuffer *buf) {
   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) ||
@@ -217,20 +223,20 @@ void gst_audiosink_chain(GstPad *pad,GstBuffer *buf) {
     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");
index ecd4416..26a1041 100644 (file)
@@ -54,7 +54,7 @@ struct _GstAudioSink {
 
   GstPad *sinkpad;
 
-  GstClockTime clocktime;
+  //GstClockTime clocktime;
   GstClock *clock;
   /* soundcard state */
   int fd;
index f383eb2..159d88d 100644 (file)
@@ -20,7 +20,7 @@
 //#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
@@ -144,6 +144,12 @@ static GstBuffer *gst_queue_pull(GstPad *pad) {
   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;
@@ -157,8 +163,19 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
   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) {
@@ -166,7 +183,7 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
     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);
@@ -186,7 +203,7 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
 //    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);
@@ -213,19 +230,17 @@ void gst_queue_push(GstConnection *connection) {
   
   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;
@@ -233,7 +248,7 @@ void gst_queue_push(GstConnection *connection) {
   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);
 
index 4016b94..bb9c47b 100644 (file)
@@ -43,7 +43,7 @@ GstElementDetails gst_queue_details;
 #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;
index d2e9669..1f08293 100644 (file)
--- a/gst/gst.h
+++ b/gst/gst.h
@@ -21,6 +21,8 @@
 #ifndef __GST_H__
 #define __GST_H__
 
+#include <unistd.h>
+
 #include <gtk/gtk.h>
 
 #include <gst/gstlog.h>
@@ -51,9 +53,9 @@ void gst_init(int *argc,char **argv[]);
 /* 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
 
index 0ea397a..b3093b5 100644 (file)
@@ -151,7 +151,7 @@ void gst_bin_add(GstBin *bin,GstElement *element) {
      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 {
@@ -199,10 +199,10 @@ static gboolean gst_bin_change_state(GstElement *element,
   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");
@@ -255,7 +255,6 @@ static gboolean gst_bin_change_state_type(GstBin *bin,
 //    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);
 
@@ -394,7 +393,7 @@ static void gst_bin_create_plan_func(GstBin *bin) {
 
   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;
@@ -404,11 +403,11 @@ static void gst_bin_create_plan_func(GstBin *bin) {
     // 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);
@@ -417,7 +416,7 @@ static void gst_bin_create_plan_func(GstBin *bin) {
 
     /* 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++;
@@ -437,7 +436,7 @@ static void gst_bin_create_plan_func(GstBin *bin) {
           /* 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)));
@@ -450,7 +449,7 @@ for internal element '%s'\n",
     }
     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) {
@@ -464,7 +463,7 @@ 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);
index 1255301..c6bcaed 100644 (file)
@@ -30,8 +30,7 @@ extern "C" {
 
 
 #define GST_BUFFER(buf) \
-       ((GstBuffer *)(buf))
-
+  ((GstBuffer *)(buf))
 
 #define GST_BUFFER_FLAGS(buf) \
   (GST_BUFFER(buf)->flags)
index 41300d3..8f453cc 100644 (file)
@@ -22,7 +22,6 @@
 #include <gstclock.h>
 
 static GstClock *the_system_clock = NULL;
-static int num;
 
 /**
  * gst_clock_new:
@@ -39,8 +38,9 @@ GstClock *gst_clock_new(gchar *name) {
   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;
 }
 
@@ -56,87 +56,83 @@ void gst_clock_register(GstClock *clock, GstObject *obj) {
   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);
 
 }
index d11e718..ba6452b 100644 (file)
@@ -43,6 +43,7 @@ struct _GstClock {
   GstClockTimeDiff adjust;
   gboolean locking;
   GList *sinkobjects;
+  gint num, num_locked;
   GMutex *sinkmutex;
   GMutex *lock;
 };
@@ -54,6 +55,7 @@ void gst_clock_register(GstClock *clock, GstObject *obj);
 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
 }
index ea6a45c..82e8a9e 100644 (file)
@@ -39,7 +39,6 @@ static void gst_element_class_init(GstElementClass *klass);
 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 };
 
@@ -265,7 +264,7 @@ void gst_element_connect(GstElement *src,gchar *srcpadname,
  * 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);
 }
@@ -331,7 +330,7 @@ gboolean gst_element_change_state(GstElement *element,
 //          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
@@ -497,7 +496,7 @@ xmlNodePtr gst_element_save_thyself(GstElement *element,xmlNodePtr parent) {
             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]));
index 4a33870..966c33e 100644 (file)
@@ -52,11 +52,11 @@ typedef enum {
 #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
 
 
index 27daada..29f577a 100644 (file)
@@ -18,6 +18,8 @@
  */
 
 
+//#define DEBUG_ENABLED
+#include <gst/gst.h>
 #include <gst/gstpad.h>
 #include <gst/gstelement.h>
 #include <gst/gsttype.h>
@@ -80,6 +82,7 @@ static void gst_pad_init(GstPad *pad) {
   pad->peer = NULL;
   pad->chain = NULL;
   pad->pull = NULL;
+  pad->qos = NULL;
   pad->parent = NULL;
   pad->ghostparents = NULL;
 }
@@ -166,6 +169,13 @@ void gst_pad_set_chain_function(GstPad *pad,GstPadChainFunction chain) {
   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));
@@ -179,9 +189,9 @@ void gst_pad_push(GstPad *pad,GstBuffer *buffer) {
   // 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);
   }
@@ -195,12 +205,12 @@ GstBuffer *gst_pad_pull(GstPad *pad) {
   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) {
@@ -208,11 +218,11 @@ GstBuffer *gst_pad_pull(GstPad *pad) {
     // 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;
@@ -230,6 +240,41 @@ void gst_pad_chain(GstPad *pad) {
     (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 */
index d48b34a..10879c1 100644 (file)
@@ -53,6 +53,7 @@ typedef struct _GstPadClass GstPadClass;
 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,
@@ -77,6 +78,7 @@ struct _GstPad {
 
   GstPadChainFunction chain;
   GstPadPullFunction pull;
+  GstPadQoSFunction qos;
 
   GstObject *parent;
   GList *ghostparents;
@@ -93,6 +95,7 @@ void gst_pad_destroy(GstPad *pad);
 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);
@@ -114,6 +117,7 @@ void gst_pad_disconnect(GstPad *srcpad,GstPad *sinkpad);
 
 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);
 
index b62f391..edcbea9 100644 (file)
@@ -105,7 +105,7 @@ GstPipeline *gst_pipeline_new(guchar *name) {
 }
 
 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)));
 }
 
 
@@ -119,13 +119,14 @@ static gboolean gst_pipeline_change_state(GstElement *element,
   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;
index c88f7e0..cc19d4b 100644 (file)
@@ -17,6 +17,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include <gst/gst.h>
 #include <gst/gstthread.h>
 
 GstElementDetails gst_thread_details = {
@@ -117,13 +118,13 @@ static void gst_thread_set_arg(GtkObject *object,GtkArg *arg,guint id) {
   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:
@@ -175,7 +176,7 @@ static void gst_thread_prepare(GstThread *thread) {
   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++;
@@ -195,7 +196,7 @@ static void gst_thread_prepare(GstThread *thread) {
           /* 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)));
@@ -208,7 +209,7 @@ for internal element \"%s\"\n",
     }
     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);
 }
 
 
@@ -227,7 +228,7 @@ static gboolean gst_thread_change_state(GstElement *element,
     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)
@@ -235,14 +236,14 @@ static gboolean gst_thread_change_state(GstElement *element,
       /* 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;
@@ -254,19 +255,19 @@ static gboolean gst_thread_change_state(GstElement *element,
       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);
@@ -288,7 +289,8 @@ static gboolean gst_thread_change_state(GstElement *element,
 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))
@@ -302,7 +304,8 @@ void *gst_thread_main_loop(void *arg) {
 
   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;
 }
 
@@ -323,6 +326,8 @@ void gst_thread_iterate(GstThread *thread) {
 
   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))
@@ -333,6 +338,7 @@ void gst_thread_iterate(GstThread *thread) {
       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(",");
 }
 
index ad4f302..2df293b 100644 (file)
@@ -52,6 +52,8 @@ void
 on_play2_activate                      (GtkMenuItem     *menuitem,
                                         gpointer         user_data)
 {
+  update_buttons(0);
+  change_state(GSTPLAY_PLAYING);
 
 }
 
@@ -60,6 +62,8 @@ void
 on_pause1_activate                     (GtkMenuItem     *menuitem,
                                         gpointer         user_data)
 {
+  update_buttons(1);
+  change_state(GSTPLAY_PAUSE);
 
 }
 
@@ -68,6 +72,8 @@ void
 on_stop1_activate                      (GtkMenuItem     *menuitem,
                                         gpointer         user_data)
 {
+  update_buttons(2);
+  change_state(GSTPLAY_STOPPED);
 
 }
 
index a1b6fe0..6ef0fd2 100644 (file)
@@ -7,6 +7,10 @@
 #  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;
@@ -31,6 +41,8 @@ static void frame_displayed(GstSrc *asrc)
   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;
@@ -53,10 +65,13 @@ static void frame_displayed(GstSrc *asrc)
   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;
 }
 
@@ -67,16 +82,31 @@ static void eof(GstSrc *src) {
 
 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;
@@ -126,12 +156,12 @@ static void have_type(GstSink *sink) {
                   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);
   }
@@ -152,6 +182,8 @@ static void have_type(GstSink *sink) {
     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);
@@ -162,10 +194,13 @@ main (int argc, char *argv[])
 {
   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);
@@ -173,28 +208,57 @@ main (int argc, char *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]));
 
@@ -215,6 +279,8 @@ main (int argc, char *argv[])
   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);
 
@@ -222,7 +288,9 @@ main (int argc, char *argv[])
 
   change_state(GSTPLAY_PLAYING);
 
+  gdk_threads_enter();
   gtk_main();
+  gdk_threads_leave();
   return 0;
 }
 
index f1d12ee..cb6db97 100644 (file)
@@ -1,5 +1,5 @@
 
-#define BUFFER 15
+#define BUFFER 20
 #define VIDEO_DECODER "mpeg_play"
 
 #ifdef HAVE_CONFIG_H
@@ -13,8 +13,8 @@
 
 
 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) 
 {
@@ -26,7 +26,7 @@ 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
@@ -40,7 +40,6 @@ void mpeg1_new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline)
     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),
@@ -48,7 +47,7 @@ void mpeg1_new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline)
     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");
@@ -64,15 +63,15 @@ void mpeg1_new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline)
     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;
@@ -91,7 +90,6 @@ void mpeg1_setup_video_thread(GstPad *pad, GstElement *show, GstElement *pipelin
   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),
@@ -99,7 +97,7 @@ void mpeg1_setup_video_thread(GstPad *pad, GstElement *show, GstElement *pipelin
   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");
@@ -115,9 +113,7 @@ void mpeg1_setup_video_thread(GstPad *pad, GstElement *show, GstElement *pipelin
   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);
 }
 
index 3f899b8..9e0ba8b 100644 (file)
@@ -372,11 +372,11 @@ mmx_ok(void)
 #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) \
@@ -386,8 +386,8 @@ mmx_ok(void)
        __asm__ __volatile__ ("movq %0, %%mm0\n\t" \
                              #op " %1, %%mm0\n\t" \
                              "movq %%mm0, %0" \
-                             : "=X" (memd) \
-                             : "X" (mems))
+                             : "=m" (memd) \
+                             : "m" (mems))
 
 #endif
 
index b136419..6c0a249 100644 (file)
@@ -147,9 +147,8 @@ static void gst_audiosink_init(GstAudioSink *audiosink) {
   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) {
@@ -173,19 +172,20 @@ 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));
@@ -197,6 +197,12 @@ void gst_audiosink_chain(GstPad *pad,GstBuffer *buf) {
   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) ||
@@ -217,20 +223,20 @@ void gst_audiosink_chain(GstPad *pad,GstBuffer *buf) {
     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");
index ecd4416..26a1041 100644 (file)
@@ -54,7 +54,7 @@ struct _GstAudioSink {
 
   GstPad *sinkpad;
 
-  GstClockTime clocktime;
+  //GstClockTime clocktime;
   GstClock *clock;
   /* soundcard state */
   int fd;
index f383eb2..159d88d 100644 (file)
@@ -20,7 +20,7 @@
 //#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
@@ -144,6 +144,12 @@ static GstBuffer *gst_queue_pull(GstPad *pad) {
   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;
@@ -157,8 +163,19 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
   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) {
@@ -166,7 +183,7 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
     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);
@@ -186,7 +203,7 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
 //    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);
@@ -213,19 +230,17 @@ void gst_queue_push(GstConnection *connection) {
   
   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;
@@ -233,7 +248,7 @@ void gst_queue_push(GstConnection *connection) {
   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);
 
index 4016b94..bb9c47b 100644 (file)
@@ -43,7 +43,7 @@ GstElementDetails gst_queue_details;
 #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;