This is the audio/video sync release.

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.
This commit is contained in:
Wim Taymans 2000-07-12 22:52:42 +00:00
parent 37576c7dc9
commit 9920b88c3f
25 changed files with 450 additions and 206 deletions

View 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)

79
docs/random/states.new Normal file
View file

@ -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.

View 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");

View file

@ -54,7 +54,7 @@ struct _GstAudioSink {
GstPad *sinkpad;
GstClockTime clocktime;
//GstClockTime clocktime;
GstClock *clock;
/* soundcard state */
int fd;

View 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);

View 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;

View file

@ -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

View 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);

View file

@ -30,8 +30,7 @@ extern "C" {
#define GST_BUFFER(buf) \
((GstBuffer *)(buf))
((GstBuffer *)(buf))
#define GST_BUFFER_FLAGS(buf) \
(GST_BUFFER(buf)->flags)

View 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;
g_mutex_lock(clock->lock);
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);
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);
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);
}

View 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
}

View 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]));

View 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

View 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 */

View 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);

View 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;

View 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(",");
}

View 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);
}

View file

@ -7,6 +7,10 @@
# include <config.h>
#endif
//#define DEBUG_ENABLED
#include <gst/gstclock.h>
#include "gstplay.h"
#include "interface.h"
@ -14,9 +18,15 @@
#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"));
pipeline = gst_pipeline_new("pipeline");
g_return_val_if_fail(pipeline != NULL, -1);
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);
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;
}

View 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);
}

View 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

View 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");

View file

@ -54,7 +54,7 @@ struct _GstAudioSink {
GstPad *sinkpad;
GstClockTime clocktime;
//GstClockTime clocktime;
GstClock *clock;
/* soundcard state */
int fd;

View 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);

View 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;