mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-22 09:41:07 +00:00
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:
parent
37576c7dc9
commit
9920b88c3f
25 changed files with 450 additions and 206 deletions
26
configure.in
26
configure.in
|
@ -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
79
docs/random/states.new
Normal 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.
|
|
@ -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)
|
||||
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));
|
||||
//audiosink->clocktime += (1000000LL*GST_BUFFER_SIZE(buf)/(audiosink->channels*
|
||||
// (audiosink->format/8)*(audiosink->frequency)));
|
||||
//g_print("audiosink: writing to soundcard ok\n");
|
||||
//gst_clock_set(audiosink->clock, GST_BUFFER_TIMESTAMP(buf));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
end:
|
||||
//g_print("a unref\n");
|
||||
gst_buffer_unref(buf);
|
||||
//g_print("a done\n");
|
||||
|
|
|
@ -54,7 +54,7 @@ struct _GstAudioSink {
|
|||
|
||||
GstPad *sinkpad;
|
||||
|
||||
GstClockTime clocktime;
|
||||
//GstClockTime clocktime;
|
||||
GstClock *clock;
|
||||
/* soundcard state */
|
||||
int fd;
|
||||
|
|
|
@ -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;
|
||||
|
@ -158,7 +164,18 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
|
|||
|
||||
/* 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,27 +230,25 @@ 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");
|
||||
STATUS("%s: U\n");
|
||||
g_cond_wait(queue->emptycond,queue->emptylock);
|
||||
g_mutex_unlock(queue->emptylock);
|
||||
GST_LOCK(queue);
|
||||
}
|
||||
}
|
||||
|
||||
front = queue->queue;
|
||||
buf = (GstBuffer *)(front->data);
|
||||
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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
23
gst/gstbin.c
23
gst/gstbin.c
|
@ -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);
|
||||
|
|
|
@ -32,7 +32,6 @@ extern "C" {
|
|||
#define GST_BUFFER(buf) \
|
||||
((GstBuffer *)(buf))
|
||||
|
||||
|
||||
#define GST_BUFFER_FLAGS(buf) \
|
||||
(GST_BUFFER(buf)->flags)
|
||||
#define GST_BUFFER_FLAG_IS_SET(buf,flag) \
|
||||
|
|
|
@ -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);
|
||||
//DEBUG("gst_clock: 0x%p waiting for time %llu %llu %lld %llu\n", obj, time, target, diff, now);
|
||||
if (!tfnow.tv_sec) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
//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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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]));
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
55
gst/gstpad.c
55
gst/gstpad.c
|
@ -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);
|
||||
}
|
||||
|
@ -200,7 +210,7 @@ GstBuffer *gst_pad_pull(GstPad *pad) {
|
|||
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");
|
||||
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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(",");
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
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));
|
||||
//audiosink->clocktime += (1000000LL*GST_BUFFER_SIZE(buf)/(audiosink->channels*
|
||||
// (audiosink->format/8)*(audiosink->frequency)));
|
||||
//g_print("audiosink: writing to soundcard ok\n");
|
||||
//gst_clock_set(audiosink->clock, GST_BUFFER_TIMESTAMP(buf));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
end:
|
||||
//g_print("a unref\n");
|
||||
gst_buffer_unref(buf);
|
||||
//g_print("a done\n");
|
||||
|
|
|
@ -54,7 +54,7 @@ struct _GstAudioSink {
|
|||
|
||||
GstPad *sinkpad;
|
||||
|
||||
GstClockTime clocktime;
|
||||
//GstClockTime clocktime;
|
||||
GstClock *clock;
|
||||
/* soundcard state */
|
||||
int fd;
|
||||
|
|
|
@ -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;
|
||||
|
@ -158,7 +164,18 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
|
|||
|
||||
/* 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,27 +230,25 @@ 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");
|
||||
STATUS("%s: U\n");
|
||||
g_cond_wait(queue->emptycond,queue->emptylock);
|
||||
g_mutex_unlock(queue->emptylock);
|
||||
GST_LOCK(queue);
|
||||
}
|
||||
}
|
||||
|
||||
front = queue->queue;
|
||||
buf = (GstBuffer *)(front->data);
|
||||
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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue