initial checkin

Original commit message from CVS:
initial checkin
This commit is contained in:
Erik Walthinsen 2000-01-30 10:44:33 +00:00
parent 1762dfbf98
commit 0ec400890c
99 changed files with 7268 additions and 0 deletions

1
docs/Makefile.am Normal file
View file

@ -0,0 +1 @@
#EXTRA_DIST = random slides

78
docs/random/arch Normal file
View file

@ -0,0 +1,78 @@
GstElementFactory:
Base class for all elementfactories. Is a single-instance (per program)
object that creates objects of the associated GstElement derivative.
GstPlugin:
Defines a given plugin. Records plugin name, function pointers, details,
etc. Includes a list of GstElementFactories that are associated with
this plugin.
GstBuffer
GstPad
GstObject
GstSrc
GstDiskSrc
GstHTTPSrc
*
GstAsyncSrc
GstAsyncDiskSrc
*
GstFilter
GstVideoFilter
GstVideoMPEG
*
GstAudioFilter
GstAudioMPEG
*
*
GstSink
GstAudioSink
GstAudioOSSSink
GstAudioALSASink
GstAudioESDSink
*
GstVideoSink
GstVideoGDKRGBSink
GstVideoXvSink
*
*
*
GstBin
GstPipeline
GstThread
GstConnection
GstQueue
GstNetwork
GstSHM
GstObject:
Base class for all streamer objects (duh), defines some basic stuff like a
pointer to the master pipeline for the object.
GstBin:
Contains a bunch of GstObjects.
GstPipeline:
A bin that can be used raw in an application. The object that gets
embedded into applications. Can contain any set of GstObjects. Nothing
but a convenience object for the moment, will eventually be *the* object
dealt with externally.
GstThread:
A bin that will become a thread if possible when the pipeline is started
up. Can contain any set of GstObjects except another GstThread. All
starting points and/or clocked events must be registered with this object,
to be dealt with in the separate thread.

15
docs/random/buffers Normal file
View file

@ -0,0 +1,15 @@
Buffer mutability properties are the most important part of gst, and
similarly are the most complex.
The simple case is that a buffer is created, memory allocated, data put
in it, and passed to the next filter. That filter reads the data, does
something (like creating a new buffer and decoding into it), and
unreferences the buffer. This causes the data to be freed and the buffer
to be destroyed.
A more complex case is when the filter modifies the data in place. It
does so and simply passes on the buffer to the next element. This is just
as easy to deal with.
If the second filter adds metadata to the buffer, it just has to add the
pointer to the list. The next element simply traverses the list and

5
docs/random/coroutines Normal file
View file

@ -0,0 +1,5 @@
In a cothread-based container, all elements are run as cothreads.
Chain-function based elements are wrapped by a generic element-class
function that just calls the chain function repeatedly after pulling a
buffer for it. (in reality, chain functions are only usable in the
single-input case)

12
docs/random/design Normal file
View file

@ -0,0 +1,12 @@
The fundamental component of GStreamer is the "element", an object that
sources and/or sinks data. Elements are connected to each other via
"pads", which are extremely light-weight generic connections. Elements
can be contained inside "bins", which themselves are elements.
A pipeline consists of any number of elements, connected to each other one
after another. A source would connect to one end of a decoder, which in
turn would be connected (on the other end) to a sink, such as a sound
card. Other elements can be located anywhere in the pipeline, including
tees and transcoders.

104
docs/random/example Normal file
View file

@ -0,0 +1,104 @@
Here's a pipeline that does audio/video MPEG streams with a queue on
either side of each decompressor, for a total of 5 threads (read/split,
decode audio, decode video, play audio, play video):
NOTES: mpegsplit is the intelligence in this pipeline, providing an IDL
that allows one to connect things to a GUI.
Pipeline(mpegplay)
Thread(reader)
Element(:disk_async_src) [StreamerAsyncSrc]
OutPad(disk1)
Element(:mpegsplit)
InPad(disk1)
OutPad(audio1)
OutPad(video1)
Queue(audioQ1)
InPad(audio1)
OutPad(audio2)
Thread(audiodecode)
Element(:mpeg_audio_decode) [StreamerVideoFilter]
InPad(audio2)
OutPad(audio3)
Queue(audioQ2)
InPad(audio3)
OutPad(audio4)
Thread(audioplay)
Element(:audio_play) [StreamerAudioSink]
InPad(audio4)
Queue(videoQ1)
InPad(video1)
OutPad(video2)
Thread(videodecode)
Element(:mpeg_video_decode) [StreamerVideoFilter]
InPad(video2)
OutPad(video3)
Queue(videoQ2)
InPad(video3)
OutPad(video4)
Thread(videoplay)
Element(:video_play) [StreamerVideoSink]
InPad(video4)
A simpler pipeline that just does MPEG videos:
Pipeline(mpegplay)
Thread(reader)
Element(:disk_async_src) [GstAsyncSrc]
OutPad(disk1)
Element(:mpeg_control)
InPad(disk1)
OutPad(video1)
Element(:mpeg_video_decode) [GstVideoFilter]
InPad(video1)
InPad(video2)
Queue(queue)
InPad(video2)
OutPad(video3)
Thread(play)
Element(:video_play) [GstVideoSink]
InPad(video3)
The code for the above looks roughly like:
/* all the objects we're worried about */
GstPipeline *mpegplay;
GstThread *reader;
GstSrc *disk_src;
GstControl *mpeg_control;
GstFilter *mpeg_video_decode;
GstQueue *queue;
GstThread *play;
GstSink *video_play;
/*** first we create all of the objects ***/
mpegplay = gst_pipeline_new();
reader = gst_thread_new();
disk_src = gst_async_disk_src_new("filename.mpg");
mpeg_control = gst_mpeg_control_new();
mpeg_video_decode = gst_mpeg_video_decode_new();
queue = gst_queue_new();
play = gst_thread_new();
video_play = gst_video_sink_new();
/*** now we start to create the pipeline ***/
/* first set up the reader thread */
gst_bin_add(reader,disk_src);
gst_object_connect(disk_src,"out",mpeg_control,"in");
gst_object_connect(mpeg_control,"out",mpeg_audio_decode,"in");
gst_bin_ghost_pad(reader,mpeg_audio_decode,"out");
/* then set up the player thread */
gst_bin_add(play,audio_play);
gst_bin_ghost_pad(play,audio_play,"in");
/* now plug them all into the main pipeline */
gst_bin_add(mp3play,reader);
gst_object_connect(reader,"out",queue,"in");
gst_object_connect(queue,"out",play,"in");

7
docs/random/factoryinfo Normal file
View file

@ -0,0 +1,7 @@
short name
class
long name
descripion
author
version
copyright

4
docs/random/gboolean Normal file
View file

@ -0,0 +1,4 @@
NOTE TO SELF:
there are a lot of routines here that should be returning gboolean's for
status, rather than just plain failing.

17
docs/random/intro Normal file
View file

@ -0,0 +1,17 @@
GNOME Streamer is a pipeline-based media streaming framework. It is built
on top of the Gtk+ object model, and while it currently sits on top of
gtk, it can be divorced from it at any point in the future.
A pipeline consists of at one or more each of sources, sinks, and filters.
These elements may be combined inside container elements, which may have
their own specific properties, and act as any other element. Each element
has one or more pads, which are connection points. These pads are
connected to chain from one element to the next, providing a path along
which buffers are passed.
Operation of the pipeline is fully automatic once a buffer is put in the
front of the pipeline. As each element finishes its processing, it pushes
the buffer to the next element through an indirect function call, by way
of the two connected pads.

77
docs/random/metadata Normal file
View file

@ -0,0 +1,77 @@
The point of the metadata is to provide some context for each buffer. In
the case of audio data, for instance, it would provide the samplerate, bit
depth, and channel count.
The trick is that there may be multiple types of metadata ganged onto a
single buffer. This is why they're going to be a GList. This does mean
extra overhead in all cases, but I think it's minimal. The GList type
uses a chunk allocater so we're not wasting too much memory or time when
adding to the list.
The trick is dealing with these structs as they pass through a pipeline,
since they have potentially different mutability properties. For
instance, if you've got a mp3 decoder connected to a tee, which sends the
buffers off to both the decoder and a spectrum analyzer (and then a
visualization element). The preferred setup would be where every time a
audio/raw metadata comes down the pipe (indicating a potential change in
audio format), the audiosink and spectrum would just save off pointers.
So when exactly does this metadata go away (deallocated)? Well, that
means metadata has to be refcounted. But that gets rather hairy. OK, in
the simple case you create a metadata struct, it comes with refcount set
to 1. You pass it through, it stays one, eventually someone drops the
last reference on the buffer it's tied to, you free the metadata too.
Easy. What if you tee? You could go through and for every metadata in
the buffer, increment the refcount by the same as the buffer. So in the
above case (tee'd), the audiosink and spectrum would get the buffer with a
refcount of 2, and it'd have a metadata with refcount 2. Do they ref it
each themselves, then unref the buffer? Or do they remove the metadata?
Removing the metadata would require a buffer CoW, which would suck, so
yes, they'd just ref the metadata.
But.... what if they're all in different threads? Then we're off into
the magical world of mutexes. Everything with a refcount in a threaded
world must be mutexed, else you can do atomic increment and atomic
dec&test. Can this be done from C easily? Perhaps it needs to be found
from kernel includes via autoconf?
The goal in designing the way metadata will be defined and used is to keep
it as simple as possible. The basis for accomplishing this is the fact
that in order to actually use (rather than just pass) the metadata, you
have to know what the fields are, which means you have to have compiled in
support for that metadata at build time. Therefore, if you're using
metadata, you must have build-time access to the necessary include file
that defines it.
So, given that you've got an include file, it would be nice if the whole
thing could be contained there. This would limit the need to be linked
against something, or have load-time requirements as to that has to be
loaded before you are.
Given that really all metadata is is a region of memory of a given size
with a certain signature, this isn't all that hard. First you lay out the
struct that defines the metadata. Then you set up #defines that expand to
the size of the struct in question, as well as the four-cc code that
defines the type.
The work is done by a few #defines, a la the #defines used in all Gtk
objects. The first is a NEW() method that allocates the memory for the
metadata and fills in all the normal fields (type, size, utility
functions). Because of the way it's defined (as a #define, no less),
you'll have to invoke it as META_NEW(meta), since it can't return()
anything.
Another #define will check to make sure a meta is indeed that type by
verifying the type code and size. Theoretically, meta types can overlap
with the same fourcc code, as long as they have different sizes. But I
probably ought to have a global public registry so people writing things
don't conflict. MSFT got that right, at least.
So, a hairy problem is what to do when there are utility functions
associated with one of these things. One option is to not bother with
them. This is very likely a possible solution, since metadata is supposed
to be flat memory of a given size. Not much to do to either free or copy
it, is there?

30
docs/random/mutability Normal file
View file

@ -0,0 +1,30 @@
Mutability is the property of an object that defines whether or not you
are allowed to modify it. In the context of GST, that means that if you
want to mutilate a buffer, say to do an audio effect, you may have to do
this on a copy of the buffer, if someone else has a reference on it.
The simplest sequence of events in a decoder pipeline is as follows:
1) create buffer
2) allocate and fill data region, attach to buffer
3) pass to next element
4) decode the data into new buffer, free original buffer
5) pass to next element
6) buffer gets copied to output device (sound, video, whatever)
Both of these buffers are created from malloc()'d memory, are referenced
by one and only one element at a time, and are never modified in place.
They have no special flags, and when ref==0, they're simply free()'d.
An optimization in the case of the sound card or video double buffering,
where the output buffer actually comes from the output device. In that
case the element will be aware of such things.
A more complex example is where the data is teed after being decoded, sent
to an effects or visualization object.
1) create buffer, fill from source
2) hand to decoder
3) create new buffer, decode into it, free old buffer
4) hand to tee
5) ref++, hand off to

14
docs/random/padarch Normal file
View file

@ -0,0 +1,14 @@
--src---------------------------- --sink----------------------------
| |
--srcpad--------| |--sinkpad-------
| pad_push() . . |
push() | ->chain . . ->chain | -> chain()
| . . |
----------------| |----------------
| |
chain() is the function provided by sink element
sinkpad->chain is a pointer to that function
srcpad->chain should be a copy of that pointer
pad_push() calls the function pointer srcpad->chain
push() is the function provided by the src element

15
docs/random/sequence Normal file
View file

@ -0,0 +1,15 @@
Here's a possible (huge, large, complete?) sequence of execution for an
invocation of [GIST] playing a media stream. I'll start with a mp3 audio
stream, but eventually this should be a mpeg a/v stream off the net with
rolling capture (think ReplayTV/Tivo), pausing, rewinding, etc. This
could easily be hundreds of lines by the time I'm done...
This may look a lot like C in places, simply because that's the most
efficient way of representing a given action.
gst_init();
pipeline = gst_pipeline_new();
state =
src = gst_disksrc_new("src","song.mp3");

View file

@ -0,0 +1,45 @@
So, the method of having a _start() and _stop() function for each element
just doesn't scale. In the case of pipeline/thread model with a PLAYING
state bit, I have no way of passing a state change all the way down the
graph, i.e. a thread sitting inside a supplied bin.
Proposal is to have a single state-change class function, which gets
passed a single argument (no more 'state' going along with RUNNING). This
function can be overridden by each element as necessary, but must chain to
the parent_class version of it. It does its work, just like [st]et_arg,
in a case. It checks for STATE and ~STATE, and does the appropriate
steps. All the _start() and _stop() functions get moved into this one, in
the GST_STATE_RUNNING and ~GST_STATE_RUNNING cases.
This allows bins to and derivations thereof to simply pass through any
state they don't understand. Meta-elements will also pass through.
There may need to be some mechanism that provides for setting state on
only a certain type. This can be provided as an alternate path supplied
by bins. The bin is the one that would do the work in any case. Simply
provide class function for bins that does the selective stuff, and a main
_bin_ function that calls this class function. The supplied class
function for each bin would simply check against the given GtkType before
setting its state. Derivations of GstBin would always get it.
Success chaining (gbooleans) starts to get a little hairier...
Functions:
gst_element_set_state(element,state) is called by the application to set
the state for an element (or bin).
elementclass->change_state() is the class function that actually does the
setting of the state for this element. Any subclass implementation will
chain to the parent_class's version.
gst_element_change_state(element,state) is the Element class's
implementation of the change_state() function. It simply sets the state.
gst_bin_set_state_type(element,state,type) is a specialized function for
bins only that sets the type only on elements of that type.
binclass->change_state_type() is the class function that does the
selective

71
docs/random/states Normal file
View file

@ -0,0 +1,71 @@
GST State Bits and Transition Rules (graph to follow)
-----------------------------------
These are the 'new' state bits and what they mean.
What the state bits are:
GST_STATE_COMPLETE: if the element has enough data, but is not in any kind
of running or explicitely stopped state. ready to be used.
GST_STATE_RUNNING: this is the normal state of the pipeline, where data
goes all the way through the pipeline normally.
GST_STATE_DISCOVERY: anything the element does in this state must be reset
after discovery. any data read from sync source must be cached.
GST_STATE_PREROLL: not a lot different from PLAYING, except sinks don't
render what they're getting. useful for elements that require
data to get in sync, such as an MPEG video decoder that needs
IBBPBB before starting at the next P.
Basic transition rules:
Completeness is based on the element having enough information to actually
do something. GST_STATE_COMPLETE is required for any other state to be
valid, though the only invariant is that you can't be RUNNING unless
you're COMPLETE. In fact, AFAICT, that's the *only* invariant.
The element is entirely in control of this bit at all times. There is no
way to externally change this bit except by changing the state of the
element in such a way as to effect a change.
|= GST_STATE_COMPLETE
setting whatever the last bit of info the element was looking for
(gst_object_set)
&= ~GST_STATE_COMPLETE
changing anything that invalidates the complete state of the element
Whether the element is running or not, on the other hand, is almost
entirely out of the hands of the individual element. This is generally
turned on by way of gst_element_run() as called by the parent (ultimately
by the Pipeline), which happens to optionally call a function private to
the element to prepare it. As per docs/random/gboolean, very likely this
function should return a TRUE/FALSE.
Generally, I think if there is no such function, the generic element code
should go ahead and set the state, and trigger the state_changed signal,
returning TRUE. If there is a function, call it. If it returns TRUE,
fire off the signal (since the signal is actually an Element signal
anyway, why eat another function call?). Return the result regardless.
|= GST_STATE_RUNNING
starting up the pipeline with gst_pipeline_start
~= ~GST_STATE_RUNNING
stopping the pipeline with gst_pipeline_stop, or some error state
gst_pipeline_start() simply calls the gst_element_start() function on each
of the elements in it. This sets the RUNNING bit of each element, and for
GstBin's it loops through that list. gst_pipeline_start() is just a
special case version of gst_bin_start(). All start() functions are
GstElementClass functions, meaning you can start any element the same way.
The pipeline can be stopped the same way, but more likely the pipeline
will be stopped due to some stoppage condition, such as EOF on the source
file, or the parser being told to stop the stream. In the EOF case, it
would turn its RUNNING bit off, then call the stop() class function on its
parent. This would trigger an up-hill, breath-first traversal of the
whole graph. Alternately, if each element lists its uber-parent (the
Pipeline) it can simply inform the pipeline directly, causing a
depth-first traversal just like the start() case.

80
docs/random/states.old Normal file
View file

@ -0,0 +1,80 @@
GST States and Transition Rules (graph to follow)
-------------------------------
This should be a map of possible state transitions and what triggers them.
What the states are:
GST_STATE_NEW: a new element has this, if it has nothing set except name.
GST_STATE_INCOMPLETE: any element that has some, but not enough
information to function is in this state.
GST_STATE_COMPLETE: if the element has enough data, but is not in any kind
of running or explicitely stopped state. ready to be used.
GST_STATE_DISCOVERY: anything the element does in this state must be reset
after discovery. any data read from sync source must be cached.
GST_STATE_PREROLL: not a lot different from PLAYING, except sinks don't
render what they're getting. useful for elements that require
data to get in sync, such as an MPEG video decoder that needs
IBBPBB before starting at the next P.
GST_STATE_RUNNING: this is the normal state of the pipeline, where data
goes all the way through the pipeline normally.
GST_STATE_STOPPED: an explicit stop state, different from COMPLETE in that
the state doesn't get reset.
NULL -> GST_STATE_NEW
creating an element (gst_*_new*)
GST_STATE_NEW -> GST_STATE_INCOMPLETE
setting anything in the element that isn't sufficient to bring it
to a useful state (gst_object_set)
GST_STATE_INCOMPLETE -> GST_STATE_COMPLETE
setting whatever the last bit of info the element was looking for
(gst_object_set)
GST_STATE_COMPLETE -> GST_STATE_INCOMPLETE
changing anything that invalidates the complete state of the element
GST_STATE_COMPLETE -> GST_STATE_DISCOVERY
setting the state to DISCOVERY
[ used for autoplug ]
GST_STATE_DISCOVERY -> GST_STATE_COMPLETE
setting the state !DISCOVERY
[ used when autoplug is over ]
GST_STATE_DISCOVERY -> GST_STATE_PREROLL
setting the state to PREROLL
[ you can go straight to preroll from discovery if you want ]
GST_STATE_DISCOVERY -> GST_STATE_RUNNING
setting the state to RUNNING
[ you can even go straight to running from preroll ]
GST_STATE_DISCOVERY -> GST_STATE_STOPPED
setting the state to STOPPED
[ normally you'd go from discovery to stopped when you load a src ]
GST_STATE_PREROLL -> GST_STATE_RUNNING
setting the state to RUNNING
[ preroll generally leads straight to running, as in above ]
GST_STATE_PREROLL -> GST_STATE_STOPPED
setting the state to STOPPED
[ it is possible to go to stopped, i.e load file@time ]
GST_STATE_RUNNING -> GST_STATE_PREROLL
setting the state to PREROLL
[ unsure if you'd need this state, you'd go to stopped first ]
GST_STATE_RUNNING -> GST_STATE_STOPPED
setting the state to STOPPED
[ pause. ]
GST_STATE_STOPPED -> GST_STATE_PREROLL
setting the state to PREROLL
[ if you seek to intermediate time while stopped, you'd preroll to
prepare to start running again immediately ]
GST_STATE_STOPPED -> GST_STATE_RUNNING
setting the state to RUNNING

33
docs/random/types Normal file
View file

@ -0,0 +1,33 @@
GstTypes exist to try to make sure data eveyrone is talking about the
right kind of data. They aid quite a bit in autoplugging, in fact make it
possible. Each well-formed type includes a function (typefind) that will
take one or more buffers and determine whether or not it is indeed a
stream of that type, and possible a metadata to go with it. It may
provide related metadata structure IDs (and must if it provides metadata
from the typefind function).
Because multiple elements and plugins are very likely to be using the same
types, the process of creating/finding types is designed to be done with a
single function call. All operations on GstTypes occur via their guint16
ID numbers, with the GstType structure "private" to the GST library. A
plugin wishing to use a give type would contain a static struct of type
GstTypeFactory, which lists the MIME type, possible extensions (which may
overlap the mime-types file), a typefind function, and any other cruft I
decide to add.
A plugin init function would take this typefactory and hand it to the
gst_type_new() (FIXME: badly named) function, which would first search for
that same MIME type in the current list. If it found one, it would
compare the two to see if the new one is "better". Better is defined as
having more extentions (to be merged) or a typefind function verses none.
The point of returning an existing MIME type is a result of the goal of
unifying types enough to guarantee that, for instance, all MP3 decoders
will work interchangably. If MP3 decoder A says "MIME type 'audio/mpeg'
with extensions 'mpeg3'" and decoder B says "MIME type 'audio/mpeg' with
extensions 'mp3'", we don't want to have two types defined, possibly with
two typefind functions. If we did, it's not obvious which of the two would
be tried first (luck) and if both would really identify streams as mp3
correctly in all cases. And whichever wins, we're stuck using the
associated decoder to play that stream. We lose the choice between any
valid mp3 decoder, and thus the whole point of the type system.

78
docs/random/vis-transform Normal file
View file

@ -0,0 +1,78 @@
Duh, an 'easy' way to replicate Giess's behavior:
For each frame, you have to mutate it by a transform matrix. This is
easy, thought not cheap. First you precalculate the transform matrix how
you want it, based on whatever rotations or whatever you want.
The data stored in each spot on the matrix tells you how to transform a
single pixel. The simple case is dx,dy, where both are relatively small.
The probably ought to be a byte in any case, so you can scale the
transform matrix on slow machines. A more complex case is some trick
whereby a single pixel ends up splattered in several places. Idea below.
The matrix consists of some number of 8bit arrays of the same size as the
image. They'd probably be line-interleaved or better to help with cache
effects (which are VERY serious here). Each channel represents some
aspect of the transform. The first two would likely be dx and dy, the
third might be a multiplier if that wasn't done statically.
The idea: any number of transform sets could be applied, given available
processing power. Just set the static scalar or the multiplier matrices
so you don't completely swamp the output pixels.
Note that this is fastest in 8-bit, but theoretically could be applied to
32 bit. 15 and 16 are hard, since you can't easily apply the multipliers
unless they're 1/2^n, and even then it's significantly heavier (you'd have
to mask the top n bits of each color out).
This SCREAMS for MMX, in case you haven't figured it out yet.
Unfortunatley, MMX is only directly useful for the scalar matrix, unless
you do a trick where all the pixels in that fit in 64 bits (8 8bit, 4
16bit, or 2 32bit) are always moved in a group. This is very possible,
and might be a significant perf increase by being able to use MMX all the
way through. Otherwise you have to place each pixel by extracting the MMX
stuff back into normal registers, and that just plain sucks.
A pseudo-C implementation:
----- BEGIN -----
gint x,y; /* image x and y size */
guchar old_image[x][y]; /* original image */
guchar new_image[x][y]; /* new image */
gchar x_xform[x][y]; /* dx matrix */
gchar y_xform[x][y]; /* dy matrix */
guchar s_xform[x][y]; /* intensity scalar matrix */
guchar scalar; /* global scalar */
gint i,j; /* indixes */
gulong p; /* pixel value in question */
guchar u,v,w; /* modifier variables */
/* clear the new image, we don't want anything getting in the way */
/* NOT NECESSARILY A GOOD THING, THOUGH */
memset(new_image,0,x*y);
/* loop through all the lines in the image */
for (j=0;j<y;j++) {
/* loop through all the pixels in the line */
for (i=0;i<x;i++) {
p = old_image[i][j];
u = x_xform[i][j];
v = y_xform[i][j];
w = s_xform[i][j];
new_image[i+u][j+v] = (guchar)((p<<14) / (w * scalar));
}
}
----- END -----
Note that the above really, *REALLY* sucks performance-wise. Throw it a
80x60 image and it'll swamp my poor laptop. Also note that I simply set
the pixel value, not merge it. That means you'd better be sure your
transform matrix doesn't have overlapping destinations.
Other notes about the above code: x_xform and y_xform are signed chars,
which means pixels can move in all directions. The intensity matrix is
unsigned, with a range from 0 to 255, so is the global scalar. Note the
shift of 14bits (2 * 7bits), then divide by each. That means identity for
both scalars is at 128. The FP range of each is thus 0.0 to 2.0. Very
handy.

39
docs/random/walkthrough Normal file
View file

@ -0,0 +1,39 @@
You might start by creating a source element and put it into a pipeline.
At this point both element's state would be GST_STATE_NEW, since they
don't have enough state to actually run yet. At this point you can set
the filename of the source, and possibly bytesperread and other things.
Then you'd want to discover the data type of the file you're sourcing.
This will typically be handled by the pipeline itself by calling
gst_pipeline_autoplug(), or gst_pipeline_find_pad_type(), or somesuch. The
pipeline would first set its state to GST_STATE_DISCOVERY. A gstfindtype
sink would be added to the pipeline and connected to the source. Its
HAVE_TYPE signal would be connected to a private pipeline function.
The pipeline would then set the the src state to GST_STATE_DISCOVERY, and
call the src's push() function until a the type is set by the function
connected to the gstfindtype element's signal. At this point the pipeline
would disconnect the gstfindtype element from the src, set the type of the
pad to the type returned by the gstfindtype element. At disconnection of
the find element, the src's state automatically reverts to NEW.
(The trick with the sources when they do DISCOVERY is that synchronous
sources can't go back and read data again. So perhaps I should set up a
wrapper function for the push() function that uses either a sync or
async function as provided by the src instance to provide DISCOVERY and
normal operations. It would use a [GstBufferCache] to read ahead into
memory if necessary, creating baby buffers as necessary to answer the
needs of each DISCOVERY sequence.)
If you called find_pad_type(), it would return right about now, with the
ID of the type it found. At the same time, if you have connected a signal
to the pad's SET_TYPE signal, it would fire right as the type is set by
the find_pad_type() function. This would allow your application to do its
own selection of filters to connect to the pad.
If you called autoplug(), the pipeline would make a selection of element
to connect. The element would be created (state=NEW), added to the
pipeline, and the appropriate sink pad connected to the src in question.
(Note that multi-sink elements won't be supported unless there's a really
good and obvious way to do so) The whole process would repeat until the
recently added element no longer has a src pad.

4
docs/slides/README Normal file
View file

@ -0,0 +1,4 @@
These are notes for slides to be presented at the OGI DISC Cookie Talk,
Oct 22, 1999. Outline will be text, probably written up in PowerPoint for
ease of presentation, and converted to .ps, .pdf, and .html once the talk
has been given.

9
docs/slides/abstract Normal file
View file

@ -0,0 +1,9 @@
Intro to GStreamer
GStreamer is a media-streaming architecture that I've been developing at
home for about 4 months now. It's designed to overcome some of the
problems I've seen in both the OGI Pipeline and in reading through
DirectShow docs. After an overview of the existing OGI Pipeline, I'll
cover GStreamer's existing and planned architecture, and list what remains
to be done. GStreamer is mostly frozen right now, as it is to be released
as 0.1.0 on Oct 31. Major thaw will occur in a few weeks.

10
docs/slides/abstract.save Normal file
View file

@ -0,0 +1,10 @@
Intro to GStreamer
GStreamer is a media-streaming architecture that I've been developing at
home for about 4 months now. It's designed to overcome some of the
problems I've seen in both the OGI Pipeline and in reading through
DirectShow docs. After an overview of the existing OGI Pipeline, I'll
cover GStreamer's existing and planned architecture, and list what remains
to be done. GStreamer is mostly frozen right now, as it is to be released
as 0.1.0 on Oct 31. Major thaw will occur in a few weeks.

144
docs/slides/outline Normal file
View file

@ -0,0 +1,144 @@
Introduction (1)
(sorry, no cool logo/graphic yet, ideas?)
GStreamer is a library and set of tools to build arbitrary,
reconfigurable filter graphs. It derives from the OGI Pipeline
and DirectShow (docs, no experience), and is in its second
generation (first was completed/abandonded *in* Atlanta on the
way to the Linux Expo).
0.1.0 release is scheduled for Oct 31, 1999.
Will cover Background, Goals, Design, and Futures
Why do we need this?
launch reads the command line to create the graph, from .so's
Connections (queues) are made by launcher, lots of switchout code
Argument handling is messy, at start-time only
...thus there is basically only one state: running
There is no real master process capable of seeing the whole
pipeline as a graph, so wiring A->B->C with some backchannel
(parameter, not data stream) from C to A is hard
Channels try to do IPC, file, and network I/O, excess abstraction
Goals (1)
Provide a clean way to both build graphs and write new elements
Make things easier by providing auto-connect, stock sub-graphs
Include tools sorely lacking in OGI pipeline, like editor, saves
Enable Linux to catch up with M$'s world, allowing commercial
plugins to a stable API (as of 1.0) so we don't end up with N
wheels from N-M different people (multiple projects)
Overview (1)
Object hierarchy capable of run-time discovery, based on GtkObject
Deeply nested parent-child relationships enable threads, blackboxes
Buffers can point to anything, are typed, and can carry metadata
Plugins can be loaded at any point, and registry reduces loads
Symbiotic editor lets you design/run/save graphs visually
What are filter graphs? (1)
Filters take data in and spit data out, doing something to it
Filters have N>=0 inputs and M>=0 outputs
Filter graphs are many filters connected together, like a circuit
The goal is typically to move data from 'left' to 'right', towards
some kind of user-visible conclusion, i.e. audio or video
Architecture (3?)
- Graphs of Elements
(here lies screen-grab from editor)
Element is core Object, Bins hold (and are) Elements
Pads are fundamental to an Element, are cross-wired with pointers
Since Bins hold Elements, and Bins are Elements, Bins hold Bins
'Ghostpads' provide interfaces for Bins without native interfaces
# Threads are type of Bin that actually run in separate threads
- States
(table of states, invariants, and descriptions)
COMPLETE Element has all needed information
RUNNING Element has acquired resources, ready to go
DISCOVERY ... (unimplemented)
PREROLL ... (unimplemented)
PLAYING Element is actively trading data
PAUSED Special state where things just don't run (?..)
States are used to keep elements in check
- Buffers
Buffers designed to be versatile, with arbitrary typing/metadata
Has pointer to data, length, so can point to someone else's data
Type system (crude so far) ensures buffers don't go stray
Metadata can be attached, such as the audio parameters
Ref-counting and copy-on-write avoids most copies, not complete
Sub-buffers can be created from bigger buffer, limitting copies
Gtk+ Object System (2)
- Pros
C-language object system, well tested (Gtk+, Gnome...)
Arguments of any fundamental type, read/write, built-in hooks
Signals used for hooks into object events, overridable
Run-time discovery of args, signals (quarks)
- Cons
No multiple-inheritance, though I haven't *needed* it
There are some holes (can't attach quarks to *eveything*)
- Design
Classes, instances are structs; 1st item is parent class
Type system allows clean casting, ^^^^^^
Arguments are set/get by string, use functions to do the work,
thus setting an arg might trigger a redraw of the GUI
Signals are strings, use marshallers, various firing methods
Basic GStreamer objects (1)
- Elements
(show class,instance structs)
Very simple, just provides a means to handle pads, state
- Bins
(show class,instance structs)
Supports children, handles group state transitions
Pads (1)
Pad list type, direction, and chaining function ptr
When creating a sink pad (!src) you set the chaining function
gst_pad_connect() sets the peers, and copies chain function to src
Passing buffer to a src pad transparently calls the chain function
(graph goes here...)
Sources (1)
Source provides functions to push data
Regular push() function just takes next N bytes and sends them
Async push_region() grabs N bytes at offset O and sends them
EOF signal [will] reset the state from PLAYING down to !RUNNING
"location" argument is global by convention, for filenames...URIs
Connections (1)
Special type of Filter that
Threads (1)
Special case of Bin that actually creates a thread transparently
When RUNNING, thread exists, mutex/cond used to go [!]PLAYING
Automatically determines how to start sub-graph
Looks for both Sources and Elements wired to Connection
Will cooperate with Pipelines when threading is not available
Typing and Metadata (1)
- Types
Based on MIME types, set up as quarks, and dealt with as int
Usable entirely at run-time, since they're registerable by plugins
- Metadata
Also registered as an int, but must be compile time due to structs
Have refcounts and CoW semantics, since they travel with buffers
Plugins (1)
Plugin architecture designed around class system
Arguments and signals provide interface over standard base class
Each Element defined by ElementFactory, which is queried by name
At plugin load, any number of ElementFactories and Types registered
Element registers against Type as source or sink
Editor (2+?)
(show filter graph snapshot, a different one, more complex)
Built as a parallel object hierarchy on top of GNOME Canvas
Every object in filter graph has equivalent in editor, plus some
Canvas is designed with groups and signal-propagation, so...
Why not build the whole thing as subclasses of CanvasGroup?
...because updates get messy/recursive (the way I *was* doing it)
Solution is to modify objects so they own Group rather than being
Relatively trivial modification, but requires lots of repointering
Still a genealogical mess of parents and children...
XML
The goal is to use XML heavily, with an eye towards DOM
Used for both saving and providing pre-build components
Both graph and editor will have namespace, they'll interleave
A generic save function will exist for Elements, with hooks
Saving an EditorElement will also save Element
Also used for a plugin registry, to avoid loading all plugins
leaky bucket is trivial
applications - generic conferencing tool (repluggable codecs), mixing
environment (data flow graphs)

17
docs/slides/slides Normal file
View file

@ -0,0 +1,17 @@
Introduction
Why do we need this?
Goals
Overview
What are filter graphs?
Gtk+ Object System
Architecture - Elements
Pads
Architecture - Buffers
Typing and Metadata
Sources
Threads and Connections
Architecture - States
Plugins
Editor
XML
Futures

32
editor/Makefile.am Normal file
View file

@ -0,0 +1,32 @@
LDFLAGS = $(GLIB_LIBS) $(GTK_LIBS) $(top_srcdir)/gst/libgst.la \
$(shell gnome-config --libs gnomeui)
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) -I$(top_srcdir)/gst \
$(shell gnome-config --cflags gnomeui)
lib_LTLIBRARIES = libgsteditor.la
libgsteditor_la_SOURCES = \
gsteditor.c \
gsteditorelement.c \
gsteditorbin.c \
gsteditorcanvas.c \
gsteditorpad.c \
gsteditorconnection.c \
gstelementselect.c \
gsteditorcreate.c
libgsteditorincludedir = $(includedir)/gst
libgsteditorinclude_HEADERS = \
gsteditor.h
bin_PROGRAMS = editor
editor_LDFLAGS = libgsteditor.la
noinst_HEADERS = \
gstelementselect.h \
gsteditorcreate.h
EXTRA_DIST = editor.glade editorelement.glade

49
editor/editor.c Normal file
View file

@ -0,0 +1,49 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gtk/gtk.h>
#include <gnome.h>
#include <libgnomeui/gnome-canvas.h>
#include <gst/gst.h>
#include "gsteditor.h"
extern gboolean _gst_plugin_spew;
int main(int argc,char *argv[]) {
GtkWidget *appwindow;
GstEditor *editor;
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
gst_plugin_load_all();
gnome_init("GST Graph Editor",VERSION,argc,argv);
appwindow = gnome_app_new("gst-editor","GST Graph Editor");
editor = gst_editor_new("pipeline");
gtk_widget_set_usize(GTK_WIDGET(editor),250,250);
gnome_app_set_contents(GNOME_APP(appwindow),GTK_WIDGET(editor));
gtk_widget_show_all(appwindow);
gtk_main();
return(0);
}

74
editor/editor.glade Normal file
View file

@ -0,0 +1,74 @@
<?xml version="1.0"?>
<GTK-Interface>
<project>
<name>project1</name>
<directory></directory>
<source_directory></source_directory>
<pixmaps_directory>pixmaps</pixmaps_directory>
<language>C</language>
<gnome_support>True</gnome_support>
<gettext_support>True</gettext_support>
<use_widget_names>False</use_widget_names>
<main_source_file>gladesrc.c</main_source_file>
<main_header_file>gladesrc.h</main_header_file>
<handler_source_file>gladesig.c</handler_source_file>
<handler_header_file>gladesig.h</handler_header_file>
</project>
<widget>
<class>GtkWindow</class>
<name>editor_window</name>
<title>GST Editor</title>
<type>GTK_WINDOW_TOPLEVEL</type>
<position>GTK_WIN_POS_NONE</position>
<allow_shrink>False</allow_shrink>
<allow_grow>True</allow_grow>
<auto_shrink>False</auto_shrink>
<widget>
<class>GtkVBox</class>
<name>vbox3</name>
<homogeneous>False</homogeneous>
<spacing>0</spacing>
<widget>
<class>Custom</class>
<name>canvas_custom</name>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
</child>
<creation_function>create_canvas</creation_function>
<int1>0</int1>
<int2>0</int2>
</widget>
<widget>
<class>GtkHBox</class>
<name>hbox3</name>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
</child>
<homogeneous>False</homogeneous>
<spacing>0</spacing>
<widget>
<class>GtkButton</class>
<name>create_button</name>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
<can_focus>True</can_focus>
<label>Add Element</label>
</widget>
</widget>
</widget>
</widget>
</GTK-Interface>

143
editor/editorelement.glade Normal file
View file

@ -0,0 +1,143 @@
<?xml version="1.0"?>
<GTK-Interface>
<project>
<name>project1</name>
<directory></directory>
<source_directory></source_directory>
<pixmaps_directory>pixmaps</pixmaps_directory>
<language>C</language>
<gnome_support>True</gnome_support>
<gettext_support>True</gettext_support>
<use_widget_names>False</use_widget_names>
<main_source_file>gladesrc.c</main_source_file>
<main_header_file>gladesrc.h</main_header_file>
<handler_source_file>gladesig.c</handler_source_file>
<handler_header_file>gladesig.h</handler_header_file>
</project>
<widget>
<class>GtkWindow</class>
<name>window1</name>
<title>window1</title>
<type>GTK_WINDOW_TOPLEVEL</type>
<position>GTK_WIN_POS_NONE</position>
<allow_shrink>False</allow_shrink>
<allow_grow>True</allow_grow>
<auto_shrink>False</auto_shrink>
<widget>
<class>GtkFrame</class>
<name>element</name>
<border_width>25</border_width>
<label>mpegparse</label>
<label_xalign>0</label_xalign>
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
<widget>
<class>GtkHBox</class>
<name>hbox1</name>
<homogeneous>False</homogeneous>
<spacing>0</spacing>
<widget>
<class>GtkVBox</class>
<name>vbox1</name>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
</child>
<homogeneous>False</homogeneous>
<spacing>0</spacing>
<widget>
<class>GtkFrame</class>
<name>frame5</name>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
<label_xalign>0</label_xalign>
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
<widget>
<class>GtkLabel</class>
<name>src</name>
<label>src</label>
<justify>GTK_JUSTIFY_CENTER</justify>
<xalign>0.5</xalign>
<yalign>0.5</yalign>
<xpad>0</xpad>
<ypad>0</ypad>
</widget>
</widget>
</widget>
<widget>
<class>Placeholder</class>
</widget>
<widget>
<class>GtkVBox</class>
<name>vbox3</name>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
</child>
<homogeneous>False</homogeneous>
<spacing>0</spacing>
<widget>
<class>GtkFrame</class>
<name>frame3</name>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
<label_xalign>0</label_xalign>
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
<widget>
<class>GtkLabel</class>
<name>audiosrc</name>
<label>audiosrc</label>
<justify>GTK_JUSTIFY_CENTER</justify>
<xalign>0.5</xalign>
<yalign>0.5</yalign>
<xpad>0</xpad>
<ypad>0</ypad>
</widget>
</widget>
<widget>
<class>GtkFrame</class>
<name>frame4</name>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
</child>
<label_xalign>0</label_xalign>
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
<widget>
<class>GtkLabel</class>
<name>videosrc</name>
<label></label>
<justify>GTK_JUSTIFY_CENTER</justify>
<xalign>0.5</xalign>
<yalign>0.5</yalign>
<xpad>0</xpad>
<ypad>0</ypad>
</widget>
</widget>
</widget>
</widget>
</widget>
</widget>
</GTK-Interface>

144
editor/gsteditor.c Normal file
View file

@ -0,0 +1,144 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gtk/gtk.h>
#include <gnome.h>
#include <gst/gst.h>
#include "gsteditor.h"
/* signals and args */
enum {
LAST_SIGNAL
};
enum {
ARG_0,
ARG_NAME,
};
static void gst_editor_class_init(GstEditorClass *klass);
static void gst_editor_init(GstEditor *editor);
static void gst_editor_set_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_get_arg(GtkObject *object,GtkArg *arg,guint id);
static GtkFrame *parent_class = NULL;
GtkType gst_editor_get_type(void) {
static GtkType editor_type = 0;
if (!editor_type) {
static const GtkTypeInfo editor_info = {
"GstEditor",
sizeof(GstEditor),
sizeof(GstEditorClass),
(GtkClassInitFunc)gst_editor_class_init,
(GtkObjectInitFunc)gst_editor_init,
NULL,
NULL,
(GtkClassInitFunc)NULL,
};
editor_type = gtk_type_unique(gtk_frame_get_type(),&editor_info);
}
return editor_type;
}
static void gst_editor_class_init(GstEditorClass *klass) {
GtkObjectClass *object_class;
object_class = (GtkObjectClass*)klass;
parent_class = gtk_type_class(gtk_frame_get_type());
gtk_object_add_arg_type("GstEditor::name",GTK_TYPE_STRING,
GTK_ARG_READWRITE,ARG_NAME);
object_class->set_arg = gst_editor_set_arg;
object_class->get_arg = gst_editor_get_arg;
}
static void gst_editor_init(GstEditor *editor) {
/* create the pipeline */
editor->pipeline = gst_pipeline_new("pipeline");
g_return_if_fail(editor->pipeline != NULL);
/* create the editor canvas */
editor->canvas = gst_editor_canvas_new(GST_BIN(editor->pipeline),NULL);
/* create the scrolled window */
editor->scrollwindow = gtk_scrolled_window_new(NULL,NULL);
/* get the canvas widget */
editor->canvaswidget = gst_editor_canvas_get_canvas(editor->canvas);
/* add the canvas to the scrolled window */
gtk_container_add(GTK_CONTAINER(editor->scrollwindow),
editor->canvaswidget);
/* add the scrolled window to the canvas */
gtk_container_add(GTK_CONTAINER(editor),editor->scrollwindow);
}
/**
* gst_editor_new:
* name: name of editor frame
*
* Creates a new GstEditor composite widget with the given name.
*
* Returns: Freshly created GstEditor widget.
*/
GstEditor *gst_editor_new(gchar *name) {
GstEditor *editor;
editor = gtk_type_new(gst_editor_get_type());
gtk_object_set(GTK_OBJECT(editor),"name",name,NULL);
return editor;
}
static void gst_editor_set_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditor *editor = GST_EDITOR(object);
switch (id) {
case ARG_NAME:
gtk_object_set(GTK_OBJECT(editor),"label",GTK_VALUE_STRING(*arg),NULL);
gst_element_set_name(GST_OBJECT(editor->pipeline),
GTK_VALUE_STRING(*arg));
break;
default:
g_warning("gsteditor: unknown arg!\n");
break;
}
}
static void gst_editor_get_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditor *editor = GST_EDITOR(object);
switch (id) {
case ARG_NAME:
GTK_VALUE_STRING(*arg) =
gst_element_get_name(GST_OBJECT(editor->pipeline));
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}

360
editor/gsteditor.h Normal file
View file

@ -0,0 +1,360 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_EDITOR_H__
#define __GST_EDITOR_H__
#include <gnome.h>
#include <gst/gst.h>
typedef struct _GstEditor GstEditor;
typedef struct _GstEditorClass GstEditorClass;
typedef struct _GstEditorElement GstEditorElement;
typedef struct _GstEditorElementClass GstEditorElementClass;
typedef struct _GstEditorBin GstEditorBin;
typedef struct _GstEditorBinClass GstEditorBinClass;
typedef struct _GstEditorCanvas GstEditorCanvas;
typedef struct _GstEditorCanvasClass GstEditorCanvasClass;
typedef struct _GstEditorPad GstEditorPad;
typedef struct _GstEditorPadClass GstEditorPadClass;
typedef struct _GstEditorConnection GstEditorConnection;
typedef struct _GstEditorConnectionClass GstEditorConnectionClass;
#define GST_TYPE_EDITOR \
(gst_editor_get_type())
#define GST_EDITOR(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR,GstEditor))
#define GST_EDITOR_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR,GstEditorClass))
#define GST_IS_EDITOR(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR))
#define GST_IS_EDITOR_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR)))
struct _GstEditor {
GtkFrame frame;
/* the actual pipeline to be associated with this thing */
GstPipeline *pipeline;
/* the editor canvas */
GstEditorCanvas *canvas;
/* the canvas and scrollwindow */
GtkWidget *canvaswidget;
GtkWidget *scrollwindow;
};
struct _GstEditorClass {
GnomeCanvasClass parent_class;
};
GtkType gst_editor_get_type();
GstEditor *gst_editor_new(gchar *name);
#define GST_EDITOR_SET_OBJECT(item,object) \
(gtk_object_set_data(GTK_OBJECT(item),"gsteditorobject",(object)))
#define GST_EDTIOR_GET_OBJECT(item) \
(gtk_object_get_data(GTK_OBJECT(item),"gsteditorobject"))
#define GST_TYPE_EDITOR_ELEMENT \
(gst_editor_element_get_type())
#define GST_EDITOR_ELEMENT(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_ELEMENT,GstEditorElement))
#define GST_EDITOR_ELEMENT_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_ELEMENT,GstEditorElementClass))
#define GST_IS_EDITOR_ELEMENT(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_ELEMENT))
#define GST_IS_EDITOR_ELEMENT_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_ELEMENT)))
#define GST_EDITOR_ELEMENT_PARENT(obj) (GST_EDITOR_ELEMENT(obj)->parent)
#define GST_EDITOR_ELEMENT_GROUP(obj) (GST_EDITOR_ELEMENT(obj)->group)
#define GST_EDITOR_ELEMENT_CANVAS(obj) (GST_EDITOR_ELEMENT(obj)->canvas)
struct _GstEditorElement {
GstObject object;
/* parent object (NULL if I am the parent) */
GstEditorBin *parent;
/* toplevel canvas (myself if I am the toplevel) */
GstEditorCanvas *canvas;
/* the element we're associated with */
GstElement *element;
/* whether we've been realized or not */
gboolean realized;
/* toplevel group, must be !NULL */
GnomeCanvasGroup *group; // parent group
/* visual stuff */
gdouble x,y; // center
gdouble width,height; // size
GnomeCanvasItem *border,*title,*resizebox; // easy ones
GnomeCanvasItem *statebox[4],*statetext[4]; // GST_STATE_*
GnomeCanvasItem *playbox,*playtext; // playstate
gboolean states[5]; // visual states
gdouble insidewidth,insideheight; // minimum space inside
gdouble minwidth,minheight; // minimum size
gdouble titlewidth,titleheight; // size of title
gdouble statewidth,stateheight; // size of state boxes
gdouble sinkwidth,sinkheight; // size of sink pads
gdouble srcwidth,srcheight; // size of src pads
gint sinks,srcs; // how many pads?
GnomeCanvasGroup *insidegroup; // contents if any
gboolean resize; // does it need resizing?
/* list of pads */
GList *srcpads,*sinkpads;
gboolean padlistchange;
/* interaction state */
gboolean dragging,resizing,moved,hesitating;
gdouble offx,offy,dragx,dragy;
};
struct _GstEditorElementClass {
GnomeCanvasGroupClass parent_class;
void (*realize) (GstEditorElement *element);
gint (*event) (GnomeCanvasItem *item,GdkEvent *event,
GstEditorElement *element);
gint (*button_event) (GnomeCanvasItem *item,GdkEvent *event,
GstEditorElement *element);
};
GtkType gst_editor_element_get_type();
GstEditorElement *gst_editor_element_new(GstEditorBin *parent,
GstElement *element,
const gchar *first_arg_name,...);
void gst_editor_element_construct(GstEditorElement *element,
GstEditorBin *parent,
const gchar *first_arg_name,
va_list args);
void gst_editor_element_repack(GstEditorElement *element);
GstEditorPad *gst_editor_element_add_pad(GstEditorElement *element,
GstPad *pad);
#define GST_TYPE_EDITOR_BIN \
(gst_editor_bin_get_type())
#define GST_EDITOR_BIN(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_BIN,GstEditorBin))
#define GST_EDITOR_BIN_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_BIN,GstEditorBin))
#define GST_IS_EDITOR_BIN(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_BIN))
#define GST_IS_EDITOR_BIN_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_BIN)))
struct _GstEditorBin {
GstEditorElement element;
/* lists of GUI elements and connections */
GList *elements, *connections;
/* connection state */
GstEditorPad *frompad; // where the drawing started from
gboolean fromsrc; // are we connecting *from* a source?
gboolean connecting; // if we're trying to connect right now
GstEditorConnection *connection; // the connection we're operating on
GstEditorPad *ghostpad; // potential ghost pad
gboolean inpadregion; // is cursor in pad region
};
struct _GstEditorBinClass {
GstEditorElementClass parent_class;
};
GtkType gst_editor_bin_get_type();
GstEditorBin *gst_editor_bin_new(GstEditorBin *parent,GstBin *bin,
const gchar *first_arg_name,...);
#define GST_TYPE_EDITOR_CANVAS \
(gst_editor_canvas_get_type())
#define GST_EDITOR_CANVAS(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_CANVAS,GstEditorCanvas))
#define GST_EDITOR_CANVAS_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_CANVAS,GstEditorCanvasClass))
#define GST_IS_EDITOR_CANVAS(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_CANVAS))
#define GST_IS_EDITOR_CANVAS_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_CANVAS)))
struct _GstEditorCanvas {
GstEditorBin bin;
gboolean inchild;
GnomeCanvas *canvas;
};
struct _GstEditorCanvasClass {
GnomeCanvasClass parent_class;
};
GtkType gst_editor_canvas_get_type();
GstEditorCanvas *gst_editor_canvas_new(GstBin *bin,
const gchar *first_arg_name,...);
GtkWidget *gst_editor_canvas_get_canvas(GstEditorCanvas *canvas);
void gst_editor_bin_add(GstEditorBin *parent,GstEditorElement *element);
#define GST_TYPE_EDITOR_PAD \
(gst_editor_pad_get_type())
#define GST_EDITOR_PAD(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_PAD,GstEditorPad))
#define GST_EDITOR_PAD_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_PAD,GstEditorPadClass))
#define GST_IS_EDITOR_PAD(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_PAD))
#define GST_IS_EDITOR_PAD_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_PAD)))
struct _GstEditorPad {
GtkObject object;
/* parent element */
GstEditorElement *parent;
/* toplevel canvas */
GstEditorCanvas *canvas;
/* the pad we're associated with */
GstPad *pad;
/* if this is a sink (convenience) */
gboolean issrc;
/* whether we've been realized or not */
gboolean realized;
/* connections */
GstEditorConnection *connection;
GstEditorConnection *ghostconnection;
/* visual stuff */
GnomeCanvasGroup *group;
GnomeCanvasItem *border,*title,*padbox;
gboolean sinkpad; // is this a sink pad?
gdouble x,y; // location
gdouble width,height; // actual size
gdouble boxwidth,boxheight; // size of pad box
gboolean resize; // does it need resizing?
/* interaction state */
gboolean dragging,resizing,moved;
gdouble dragx,dragy;
/* connection */
// GnomeCanvasItem *connection; // can't use
//GstEditorConnection
};
struct _GstEditorPadClass {
GtkObjectClass parent_class;
void (*realize) (GstEditorPad *pad);
};
GtkType gst_editor_pad_get_type();
GstEditorPad *gst_editor_pad_new(GstEditorElement *parent,GstPad *pad,
const gchar *first_arg_name, ...);
void gst_editor_pad_construct(GstEditorPad *element,
GstEditorElement *parent,
const gchar *first_arg_name,va_list args);
void gst_editor_pad_repack(GstEditorPad *pad);
#define GST_TYPE_EDITOR_CONNECTION \
(gst_editor_connection_get_type())
#define GST_EDITOR_CONNECTION(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_CONNECTION,GstEditorConnection))
#define GST_EDITOR_CONNECTION_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_CONNECTION,GstEditorConnectionClass))
#define GST_IS_EDITOR_CONNECTION(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_CONNECTION))
#define GST_IS_EDITOR_CONNECTION_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_CONNECTION)))
struct _GstEditorConnection {
GtkObject object;
/* our parent */
GstEditorElement *parent;
/* the two pads we're connecting */
GstEditorPad *frompad, *topad;
/* is this starting at a source (convenience) */
gboolean fromsrc;
/* toplevel canvas */
GstEditorCanvas *canvas;
/* whether we've been realized or not */
gboolean realized;
/* are we a ghosted connection? */
gboolean ghost;
/* visual stuff */
GnomeCanvasItem *line;
GnomeCanvasPoints *points;
gdouble x,y; // terminating point
gboolean resize; // does it need resizing?
};
struct _GstEditorConnectionClass {
GtkObjectClass parent_class;
void (*realize) (GstEditorConnection *connection);
};
GtkType gst_editor_connection_get_type();
void gst_editor_connection_resize(GstEditorConnection *connection);
void gst_editor_connection_set_endpoint(GstEditorConnection *connection,
gdouble x,gdouble y);
void gst_editor_connection_set_endpad(GstEditorConnection *connection,
GstEditorPad *pad);
void gst_editor_connection_connect(GstEditorConnection *connection);
#endif /* __GST_EDITOR_H__ */

266
editor/gsteditorbin.c Normal file
View file

@ -0,0 +1,266 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gnome.h>
#include <gst/gst.h>
#include "gsteditor.h"
/* signals and args */
enum {
LAST_SIGNAL
};
enum {
ARG_0,
};
static void gst_editor_bin_class_init(GstEditorBinClass *klass);
static void gst_editor_bin_init(GstEditorBin *bin);
static void gst_editor_bin_set_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_bin_get_arg(GtkObject *object,GtkArg *arg,guint id);
static gint gst_editor_bin_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element);
static gint gst_editor_bin_button_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element);
static GstEditorElementClass *parent_class = NULL;
GtkType gst_editor_bin_get_type(void) {
static GtkType bin_type = 0;
if (!bin_type) {
static const GtkTypeInfo bin_info = {
"GstEditorBin",
sizeof(GstEditorBin),
sizeof(GstEditorBinClass),
(GtkClassInitFunc)gst_editor_bin_class_init,
(GtkObjectInitFunc)gst_editor_bin_init,
NULL,
NULL,
(GtkClassInitFunc)NULL,
};
bin_type = gtk_type_unique(gst_editor_element_get_type(),&bin_info);
}
return bin_type;
}
static void gst_editor_bin_class_init(GstEditorBinClass *klass) {
GstEditorElementClass *element_class;
element_class = (GstEditorElementClass*)klass;
parent_class = gtk_type_class(gst_editor_element_get_type());
element_class->event = gst_editor_bin_event;
element_class->button_event = gst_editor_bin_button_event;
}
static void gst_editor_bin_init(GstEditorBin *bin) {
GstEditorElement *element = GST_EDITOR_ELEMENT(bin);
element->insidewidth = 200;
element->insideheight = 100;
}
GstEditorBin *gst_editor_bin_new(GstEditorBin *parent,GstBin *bin,
const gchar *first_arg_name,...) {
GstEditorBin *editorbin;
va_list args;
g_return_if_fail(parent != NULL);
g_return_if_fail(GST_IS_EDITOR_BIN(parent));
g_return_if_fail(bin != NULL);
g_return_if_fail(GST_IS_BIN(bin));
editorbin = GST_EDITOR_BIN(gtk_type_new(GST_TYPE_EDITOR_BIN));
GST_EDITOR_ELEMENT(editorbin)->element = GST_ELEMENT(bin);
va_start(args,first_arg_name);
gst_editor_element_construct(GST_EDITOR_ELEMENT(editorbin),parent,
first_arg_name,args);
va_end(args);
return editorbin;
}
static gint gst_editor_bin_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element) {
GstEditorBin *bin = GST_EDITOR_BIN(element);
// g_print("bin got %d event at %.2fx%.2f\n",event->type,
// event->button.x,event->button.y);
switch (event->type) {
case GDK_BUTTON_RELEASE:
if (bin->connecting) {
// g_print("bin got release event during drag\n");
gnome_canvas_item_ungrab(
GNOME_CANVAS_ITEM(element->group),
event->button.time);
if (bin->connection->topad)
gst_editor_connection_connect(bin->connection);
else {
bin->connection->frompad->connection = NULL;
g_list_remove(bin->connections,bin->connection);
gtk_object_destroy(GTK_OBJECT(bin->connection));
bin->connection = NULL;
}
bin->connecting = FALSE;
//g_print("in bin, setting inchild for button release\n");
element->canvas->inchild = TRUE;
return TRUE;
}
break;
case GDK_MOTION_NOTIFY:
if (bin->connecting) {
gdouble x,y;
x = event->button.x;y = event->button.y;
// g_print("bin has motion during connection draw at %.2fx%.2f\n",
// x,y);
gst_editor_bin_connection_drag(bin,x,y);
return TRUE;
}
break;
default:
break;
}
if (GST_EDITOR_ELEMENT_CLASS(parent_class)->event)
return (*GST_EDITOR_ELEMENT_CLASS(parent_class)->event)(item,event,element);
}
static gint gst_editor_bin_button_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element) {
GstEditorBin *bin = GST_EDITOR_BIN(element);
GstEditorElement *newelement;
// g_print("bin got button event\n");
if (event->type != GDK_BUTTON_RELEASE) return FALSE;
gnome_canvas_item_w2i(item,&event->button.x,&event->button.y);
// g_print("calling gst_editor_create_item(,%.2f,%.2f)\n",
// event->button.x,event->button.y);
newelement = gst_editor_create_item(bin,event->button.x,event->button.y);
if (newelement != NULL);
return TRUE;
return FALSE;
}
void gst_editor_bin_start_banding(GstEditorBin *bin,GstEditorPad *pad) {
GdkCursor *cursor;
// g_print("starting to band\n");
g_return_if_fail(GST_IS_EDITOR_PAD(pad));
bin->connection = gst_editor_connection_new(bin,pad);
bin->connections = g_list_prepend(bin->connections,bin->connection);
cursor = gdk_cursor_new(GDK_SB_RIGHT_ARROW);
gnome_canvas_item_grab(
GNOME_CANVAS_ITEM(GST_EDITOR_ELEMENT(bin)->group),
GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
cursor,GDK_CURRENT_TIME);
bin->connecting = TRUE;
}
void gst_editor_bin_connection_drag(GstEditorBin *bin,
gdouble wx,gdouble wy) {
GstEditorElement *element;
gdouble bx,by;
GnomeCanvasItem *underitem, *under = NULL;
GstEditorPad *destpad;
element = GST_EDITOR_ELEMENT(bin);
bx = wx;by = wy;
gnome_canvas_item_w2i(GST_EDITOR_ELEMENT(bin)->group,&bx,&by);
// first see if we're on top of an interesting pad
underitem = gnome_canvas_get_item_at(
GST_EDITOR_ELEMENT(bin)->canvas->canvas,wx,wy);
if (underitem != NULL)
under = GST_EDTIOR_GET_OBJECT(underitem);
if ((under != NULL) && GST_IS_EDITOR_PAD(under)) {
destpad = GST_EDITOR_PAD(under);
if (destpad != bin->connection->frompad)
gst_editor_connection_set_endpad(bin->connection,destpad);
} else {
gst_editor_connection_set_endpoint(bin->connection,bx,by);
}
/* This code is a nightmare, it'll be fixed in the next minor version
if (
((bx < element->sinkwidth) ||
(bx > (element->width - element->srcwidth))) &&
((by > element->titleheight) &&
(by < (element->height - element->stateheight)))
) {
if (!bin->inpadregion) {
GstEditorPad *ghostpad;
g_print("I'd be creating a ghost pad right about now...\n");
gst_element_add_ghost_pad(
GST_EDITOR_ELEMENT(bin)->element,
bin->connection->frompad->pad);
ghostpad = gst_editor_element_add_pad(GST_EDITOR_ELEMENT(bin),
bin->connection->frompad->pad);
gst_editor_connection_set_endpad(bin->connection,ghostpad);
gtk_object_set(GTK_OBJECT(bin->connection),"ghost",TRUE,NULL);
bin->inpadregion = TRUE;
} else {
g_print("I'd be moving the ghost pad around now...\n");
}
} else {
if (bin->inpadregion) {
g_print("I'd be removing the ghost pad now...\n");
bin->inpadregion = FALSE;
}
}
*/
}
void gst_editor_bin_add(GstEditorBin *bin,GstEditorElement *element) {
/* set the element's parent */
element->parent = bin;
/* set the canvas */
if (GST_IS_EDITOR_CANVAS(bin))
element->canvas = GST_EDITOR_CANVAS(bin);
else
element->canvas = GST_EDITOR_ELEMENT(bin)->canvas;
/* add element to list of bin's children */
bin->elements = g_list_prepend(bin->elements,element);
/* add the real element to the real bin */
gst_bin_add(GST_BIN(GST_EDITOR_ELEMENT(bin)->element),element->element);
}

251
editor/gsteditorcanvas.c Normal file
View file

@ -0,0 +1,251 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gnome.h>
#include <gst/gst.h>
#include "gsteditor.h"
/* signals and args */
enum {
LAST_SIGNAL
};
enum {
ARG_0,
ARG_CANVAS,
};
static void gst_editor_canvas_class_init(GstEditorCanvasClass *klass);
static void gst_editor_canvas_init(GstEditorCanvas *editorcanvas);
static void gst_editor_canvas_set_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_canvas_get_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_canvas_realize(GstEditorElement *element);
static gint gst_editor_canvas_button_release(GtkWidget *widget,
GdkEvent *event,
GstEditorCanvas *canvas);
static gint gst_editor_canvas_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element);
//gint gst_editor_canvas_verbose_event(GtkWidget *widget,GdkEvent *event);
static GstEditorBinClass *parent_class = NULL;
GtkType gst_editor_canvas_get_type(void) {
static GtkType editor_canvas_type = 0;
if (!editor_canvas_type) {
static const GtkTypeInfo editor_canvas_info = {
"GstEditorCanvas",
sizeof(GstEditorCanvas),
sizeof(GstEditorCanvasClass),
(GtkClassInitFunc)gst_editor_canvas_class_init,
(GtkObjectInitFunc)gst_editor_canvas_init,
NULL,
NULL,
(GtkClassInitFunc)NULL,
};
editor_canvas_type = gtk_type_unique(gst_editor_bin_get_type(),&editor_canvas_info);
}
return editor_canvas_type;
}
static void gst_editor_canvas_class_init(GstEditorCanvasClass *klass) {
GstEditorElementClass *element_class;
element_class = (GstEditorElementClass*)klass;
parent_class = gtk_type_class(gst_editor_bin_get_type());
gtk_object_add_arg_type("GstEditorCanvas::canvas",GTK_TYPE_POINTER,
GTK_ARG_READABLE,ARG_CANVAS);
element_class->realize = gst_editor_canvas_realize;
}
static void gst_editor_canvas_init(GstEditorCanvas *editorcanvas) {
}
GstEditorCanvas *gst_editor_canvas_new(GstBin *bin,
const gchar *first_arg_name,...) {
GstEditorCanvas *editorcanvas;
va_list args;
g_return_if_fail(bin != NULL);
g_return_if_fail(GST_IS_BIN(bin));
editorcanvas = GST_EDITOR_CANVAS(gtk_type_new(GST_TYPE_EDITOR_CANVAS));
GST_EDITOR_ELEMENT(editorcanvas)->element = GST_ELEMENT(bin);
va_start(args,first_arg_name);
gst_editor_element_construct(GST_EDITOR_ELEMENT(editorcanvas),NULL,
first_arg_name,args);
va_end(args);
return editorcanvas;
}
static void gst_editor_canvas_realize(GstEditorElement *element) {
GstEditorCanvas *canvas = GST_EDITOR_CANVAS(element);
canvas->canvas = GNOME_CANVAS(gnome_canvas_new());
element->canvas = canvas;
gtk_signal_connect(GTK_OBJECT(canvas->canvas),
"event",
GTK_SIGNAL_FUNC(gst_editor_canvas_event),
canvas);
gtk_signal_connect_after(GTK_OBJECT(canvas->canvas),
"button_release_event",
GTK_SIGNAL_FUNC(gst_editor_canvas_button_release),
canvas);
GST_EDITOR_SET_OBJECT(canvas->canvas,canvas);
element->group = gnome_canvas_root(canvas->canvas);
gnome_canvas_item_new(element->group,gnome_canvas_rect_get_type(),
"width_units",1.0,"fill_color","white",
"outline_color","black",
"x1",-2.0,"y1",-2.0,"x2",2.0,"y2",2.0,NULL);
}
static void gst_editor_canvas_set_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditorCanvas *canvas;
canvas = GST_EDITOR_CANVAS(object);
switch (id) {
default:
g_warning("gsteditorcanvas: unknown arg!");
break;
}
}
static void gst_editor_canvas_get_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditorCanvas *canvas;
canvas = GST_EDITOR_CANVAS(object);
switch (id) {
case ARG_CANVAS:
GTK_VALUE_POINTER(*arg) = canvas->canvas;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
GtkWidget *gst_editor_canvas_get_canvas(GstEditorCanvas *canvas) {
return GTK_WIDGET(canvas->canvas);
}
static gint gst_editor_canvas_button_release(GtkWidget *widget,
GdkEvent *event,
GstEditorCanvas *canvas) {
GstEditorBin *bin = GST_EDITOR_BIN(canvas);
gdouble x,y;
GstEditorElement *element;
// g_print("canvas got button press at %.2fx%.2f\n",
// event->button.x,event->button.y);
if (event->type != GDK_BUTTON_RELEASE) return FALSE;
// if we're connecting a pair of objects in the canvas, fall through
// if (bin->connection) {
// g_print("we're in a connection, not handling\n");
// return FALSE;
// }
if (canvas->inchild) {
// g_print("inchild, not responding to button_release\n");
canvas->inchild = FALSE;
return FALSE;
}
gnome_canvas_window_to_world(GNOME_CANVAS(widget),
event->button.x,event->button.y,&x,&y);
// g_print("calling gst_editor_create_item()\n");
if (element = gst_editor_create_item(GST_EDITOR_BIN(canvas),x,y))
return TRUE;
return FALSE;
}
/* FIXME: guerilla prototype... */
void gst_editor_bin_connection_drag(GstEditorBin *bin,
gdouble wx,gdouble wy);
static gint gst_editor_canvas_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element) {
// if (GST_EDITOR_ELEMENT_CLASS(parent_class)->event)
// return (*GST_EDITOR_ELEMENT_CLASS(parent_class)->event)(
// element->group,event,element);
GstEditorBin *bin = GST_EDITOR_BIN(element);
GstEditorCanvas *canvas = GST_EDITOR_CANVAS(element);
// g_print("canvas got event %d at %.2fx%.2f\n",event->type,
// event->button.x,event->button.y);
switch (event->type) {
case GDK_BUTTON_RELEASE:
if (bin->connecting) {
// g_print("canvas got button release during drag\n");
gnome_canvas_item_ungrab(
GNOME_CANVAS_ITEM(element->group),
event->button.time);
if (bin->connection->topad)
gst_editor_connection_connect(bin->connection);
else
gtk_object_destroy(GTK_OBJECT(bin->connection));
bin->connecting = FALSE;
//g_print("finished dragging connection on canvas, setting inchild\n");
element->canvas->inchild = TRUE;
return TRUE;
} else {
// g_print("got release, calling button_release()\n");
// gst_editor_canvas_button_release(canvas->canvas,event,canvas);
return FALSE;
}
break;
case GDK_MOTION_NOTIFY:
if (bin->connecting) {
gdouble x,y;
x = event->button.x;y = event->button.y;
gnome_canvas_window_to_world(canvas->canvas,
event->button.x,event->button.y,&x,&y);
// g_print("canvas has motion during connection draw at
//%.2fx%.2f\n",
// x,y);
gst_editor_bin_connection_drag(bin,x,y);
return TRUE;
}
break;
default:
break;
}
return FALSE;
}

View file

@ -0,0 +1,289 @@
#include <gnome.h>
#include <gst/gst.h>
#include <gst/gstutils.h>
#include "gsteditor.h"
/* class functions */
static void gst_editor_connection_class_init(GstEditorConnectionClass *klass);
static void gst_editor_connection_init(GstEditorConnection *connection);
static void gst_editor_connection_set_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_connection_get_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_connection_destroy(GtkObject *object);
static void gst_editor_connection_realize(GstEditorConnection *connection);
/* events fired by items within self */
static gint gst_editor_connection_line_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorConnection *connection);
/* utility functions */
enum {
ARG_0,
ARG_X,
ARG_Y,
ARG_FROMPAD,
ARG_TOPAD,
ARG_GHOST,
};
enum {
LAST_SIGNAL
};
static GtkObjectClass *parent_class;
static guint gst_editor_connection_signals[LAST_SIGNAL] = { 0 };
GtkType gst_editor_connection_get_type() {
static GtkType connection_type = 0;
if (!connection_type) {
static const GtkTypeInfo connection_info = {
"GstEditorConnection",
sizeof(GstEditorConnection),
sizeof(GstEditorConnectionClass),
(GtkClassInitFunc)gst_editor_connection_class_init,
(GtkObjectInitFunc)gst_editor_connection_init,
NULL,
NULL,
(GtkClassInitFunc)NULL,
};
connection_type = gtk_type_unique(gtk_object_get_type(),&connection_info);
}
return connection_type;
}
static void gst_editor_connection_class_init(GstEditorConnectionClass *klass) {
GtkObjectClass *object_class;
object_class = (GtkObjectClass*)klass;
parent_class = gtk_type_class(gnome_canvas_line_get_type());
gtk_object_add_arg_type("GstEditorConnection::x",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_X);
gtk_object_add_arg_type("GstEditorConnection::y",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_Y);
gtk_object_add_arg_type("GstEditorConnection::frompad",GTK_TYPE_POINTER,
GTK_ARG_READWRITE,ARG_FROMPAD);
gtk_object_add_arg_type("GstEditorConnection::topad",GTK_TYPE_POINTER,
GTK_ARG_READWRITE,ARG_TOPAD);
gtk_object_add_arg_type("GstEditorConnection::ghost",GTK_TYPE_BOOL,
GTK_ARG_READWRITE,ARG_GHOST);
klass->realize = gst_editor_connection_realize;
object_class->set_arg = gst_editor_connection_set_arg;
object_class->get_arg = gst_editor_connection_get_arg;
object_class->destroy = gst_editor_connection_destroy;
}
static void gst_editor_connection_init(GstEditorConnection *connection) {
connection->points = gnome_canvas_points_new(2);
}
GstEditorConnection *gst_editor_connection_new(GstEditorBin *parent,
GstEditorPad *frompad) {
GstEditorConnection *connection;
g_return_if_fail(parent != NULL);
g_return_if_fail(GST_IS_EDITOR_BIN(parent));
g_return_if_fail(frompad != NULL);
g_return_if_fail(GST_IS_EDITOR_PAD(frompad));
connection = GST_EDITOR_CONNECTION(gtk_type_new(GST_TYPE_EDITOR_CONNECTION));
connection->frompad = frompad;
connection->frompad->connection = connection;
connection->fromsrc = connection->frompad->issrc;
connection->parent = parent;
gst_editor_connection_realize(connection);
return connection;
}
static void gst_editor_connection_set_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditorConnection *connection;
/* get the major types of this object */
connection = GST_EDITOR_CONNECTION(object);
switch (id) {
case ARG_X:
connection->x = GTK_VALUE_DOUBLE(*arg);
connection->resize = TRUE;
break;
case ARG_Y:
connection->y = GTK_VALUE_DOUBLE(*arg);
connection->resize = TRUE;
break;
case ARG_TOPAD:
if (connection->topad) {
if (connection->ghost)
connection->topad->ghostconnection = NULL;
else
connection->topad->connection = NULL;
}
connection->topad = GTK_VALUE_POINTER(*arg);
/* if this is the same type, refuse */
if (connection->topad &&
(connection->frompad->issrc == connection->topad->issrc))
connection->topad = NULL;
if (connection->topad) {
if (connection->ghost)
connection->topad->ghostconnection = connection;
else
connection->topad->connection = connection;
}
connection->resize = TRUE;
break;
case ARG_GHOST:
connection->ghost = GTK_VALUE_BOOL(*arg);
break;
default:
g_warning("gsteditorconnection: unknown arg!");
break;
}
gst_editor_connection_resize(connection);
}
static void gst_editor_connection_get_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditorConnection *connection;
/* get the major types of this object */
connection = GST_EDITOR_CONNECTION(object);
switch (id) {
case ARG_X:
GTK_VALUE_INT(*arg) = connection->x;
break;
case ARG_Y:
GTK_VALUE_INT(*arg) = connection->y;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
static void gst_editor_connection_realize(GstEditorConnection *connection) {
connection->points->coords[0] = 0.0;
connection->points->coords[1] = 0.0;
connection->points->coords[2] = 0.0;
connection->points->coords[3] = 0.0;
connection->line = gnome_canvas_item_new(
GST_EDITOR_ELEMENT(connection->parent)->group,
gnome_canvas_line_get_type(),
"points",connection->points,NULL);
}
static void gst_editor_connection_destroy(GtkObject *object) {
GstEditorConnection *connection = GST_EDITOR_CONNECTION(object);
gtk_object_destroy(GTK_OBJECT(connection->line));
}
void gst_editor_connection_resize(GstEditorConnection *connection) {
gdouble x1,y1,x2,y2;
if (connection->resize != TRUE) return;
connection->resize = FALSE;
// g_print("resizing connection, frompad is %p, topad is %p\n",
// connection->frompad,connection->topad);
/* calculate the new endpoints */
if (connection->topad == NULL) {
/* our base point is the source pad */
if (connection->fromsrc)
x1 = connection->frompad->x + connection->frompad->width;
else
x1 = connection->frompad->x;
y1 = connection->frompad->y + (connection->frompad->height / 2);
x2 = connection->x;
y2 = connection->y;
/* NOTE: coords are in the following state:
x1,y1: item coords relative to the element's group
x2,y2: item coords relative to the bin's group
This means translating the x1,y1 coords into world, then into bin.
*/
gnome_canvas_item_i2w(connection->frompad->parent->group,&x1,&y1);
gnome_canvas_item_w2i(GST_EDITOR_ELEMENT_GROUP(connection->parent),
&x1,&y1);
} else {
if (connection->fromsrc) {
x1 = connection->frompad->x + connection->frompad->width;
x2 = connection->topad->x;
} else {
x1 = connection->frompad->x;
x2 = connection->topad->x + connection->topad->width;
}
y1 = connection->frompad->y + (connection->frompad->height / 2);
y2 = connection->topad->y + (connection->topad->height / 2);
gnome_canvas_item_i2w(connection->frompad->parent->group,&x1,&y1);
gnome_canvas_item_w2i(GST_EDITOR_ELEMENT_GROUP(connection->parent),
&x1,&y1);
gnome_canvas_item_i2w(connection->topad->parent->group,&x2,&y2);
gnome_canvas_item_w2i(GST_EDITOR_ELEMENT_GROUP(connection->parent),
&x2,&y2);
}
connection->points->coords[0] = x1;
connection->points->coords[1] = y1;
connection->points->coords[2] = x2;
connection->points->coords[3] = y2;
gnome_canvas_item_set(connection->line,
"points",connection->points,NULL);
}
void gst_editor_connection_set_endpoint(GstEditorConnection *connection,
gdouble x,gdouble y) {
connection->x = x;
connection->y = y;
if (connection->topad) {
if (connection->ghost)
connection->topad->ghostconnection = NULL;
else
connection->topad->connection = NULL;
connection->topad = NULL;
}
connection->resize = TRUE;
gst_editor_connection_resize(connection);
}
void gst_editor_connection_set_endpad(GstEditorConnection *connection,
GstEditorPad *pad) {
// first check for the trivial case
if (connection->topad == pad) return;
// now clean up if we've changed pads
if (connection->topad) {
if (connection->ghost)
connection->topad->ghostconnection = NULL;
else
connection->topad->connection = NULL;
}
connection->topad = pad;
if (connection->ghost)
connection->topad->ghostconnection = connection;
else
connection->topad->connection = connection;
connection->resize = TRUE;
gst_editor_connection_resize(connection);
}
void gst_editor_connection_connect(GstEditorConnection *connection) {
if (connection->ghost) {
g_print("uhhh.... Boo!\n");
} else {
if (connection->fromsrc)
gst_pad_connect(connection->frompad->pad,connection->topad->pad);
else
gst_pad_connect(connection->topad->pad,connection->frompad->pad);
}
}

View file

@ -0,0 +1,61 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_EDITOR_CONNECTION_H__
#define __GST_EDITOR_CONNECTION_H__
#include <gnome.h>
#include <gst.h>
#define GST_TYPE_EDITOR_CONNECTION \
(gst_editor_connection_get_type())
#define GST_EDITOR_CONNECTION(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_CONNECTION,GstEditorConnection))
#define GST_EDITOR_CONNECTION_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_CONNECTION,GstEditorConnection))
#define GST_IS_EDITOR_CONNECTION(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_CONNECTION))
#define GST_IS_EDITOR_CONNECTION_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_CONNECTION)))
typedef struct _GstEditorConnection GstEditorConnection;
typedef struct _GstEditorConnectionClass GstEditorConnectionClass;
struct _GstEditorConnection {
GnomeCanvasLine line;
/* the two pads we're connecting */
GstEditorPad *pad1, *pad2;
gdouble fromsrc;
/* visual stuff */
gdouble x,y; // terminating point
GnomeCanvasPoints *points;
gboolean created; // has it been created?
gboolean resized; // does it need resizing?
};
struct _GstEditorConnectionClass {
GnomeCanvasGroupClass parent_class;
};
GtkType gst_editor_connection_get_type();
#endif /* __GST_EDITOR_CONNECTION_H__ */

57
editor/gsteditorcreate.c Normal file
View file

@ -0,0 +1,57 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gnome.h>
#include <gst/gst.h>
#include "gsteditor.h"
#include "gstelementselect.h"
GstEditorElement *gst_editor_create_item(GstEditorBin *bin,
gdouble x,gdouble y) {
GstElementFactory *factory;
GstElement *element;
GstEditorElement *editorelement;
GtkType itemtype;
factory = element_select_dialog();
if (factory) {
// g_print("got factory \"%s\"\n",factory->name);
element = gst_elementfactory_create(factory,factory->name);
if (element) {
if (GST_IS_BIN(element)) {
// g_print("factory is a bin\n");
editorelement = GST_EDITOR_ELEMENT(gst_editor_bin_new(
GST_EDITOR_BIN(bin),GST_BIN(element),
"x",x,"y",y,"width",50.0,"height",20.0,NULL));
} else {
// g_print("factory is an element\n");
editorelement = gst_editor_element_new(bin,element,
"x",x,"y",y,"width",50.0,"height",20.0,NULL);
}
// g_print("created element \"%s\" at %.2fx%.2f\n",
// gst_object_get_name(GST_OBJECT(element)),
// x,y);
return editorelement;
}
}
return NULL;
}

24
editor/gsteditorcreate.h Normal file
View file

@ -0,0 +1,24 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gsteditor.h"
GstEditorElement *gst_editor_create_item(GstEditorBin *bin,
gdouble x,gdouble y);

927
editor/gsteditorelement.c Normal file
View file

@ -0,0 +1,927 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gnome.h>
#include <gst/gst.h>
#include <gst/gstutils.h>
#include "gsteditor.h"
/* class functions */
static void gst_editor_element_class_init(GstEditorElementClass *klass);
static void gst_editor_element_init(GstEditorElement *element);
static void gst_editor_element_set_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_element_get_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_element_realize(GstEditorElement *element);
static gint gst_editor_element_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element);
/* events fired by items within self */
static gint gst_editor_element_resizebox_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element);
static gint gst_editor_element_group_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element);
static gint gst_editor_element_state_event(GnomeCanvasItem *item,
GdkEvent *event,
gpointer data);
/* external events (from GstElement) */
static void gst_editor_element_state_change(GstElement *element,
gint state,
GstEditorElement *editorelement);
/* utility functions */
static void gst_editor_element_resize(GstEditorElement *element);
static void gst_editor_element_set_state(GstEditorElement *element,
gint id,gboolean set);
static void gst_editor_element_sync_state(GstEditorElement *element);
static void gst_editor_element_move(GstEditorElement *element,
gdouble dx,gdouble dy);
static gchar *_gst_editor_element_states[] = { "C","R","D","P" };
enum {
ARG_0,
ARG_X,
ARG_Y,
ARG_WIDTH,
ARG_HEIGHT,
ARG_X1,
ARG_Y1,
ARG_X2,
ARG_Y2,
ARG_ELEMENT,
};
enum {
LAST_SIGNAL
};
static GtkObjectClass *parent_class;
static guint gst_editor_element_signals[LAST_SIGNAL] = { 0 };
GtkType gst_editor_element_get_type() {
static GtkType element_type = 0;
if (!element_type) {
static const GtkTypeInfo element_info = {
"GstEditorElement",
sizeof(GstEditorElement),
sizeof(GstEditorElementClass),
(GtkClassInitFunc)gst_editor_element_class_init,
(GtkObjectInitFunc)gst_editor_element_init,
NULL,
NULL,
(GtkClassInitFunc)NULL,
};
element_type = gtk_type_unique(gtk_object_get_type(),&element_info);
}
return element_type;
}
static void gst_editor_element_class_init(GstEditorElementClass *klass) {
GtkObjectClass *object_class;
object_class = (GtkObjectClass*)klass;
parent_class = gtk_type_class(gtk_object_get_type());
gtk_object_add_arg_type("GstEditorElement::x",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY,
ARG_X);
gtk_object_add_arg_type("GstEditorElement::y",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY,
ARG_Y);
gtk_object_add_arg_type("GstEditorElement::width",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY,
ARG_WIDTH);
gtk_object_add_arg_type("GstEditorElement::height",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY,
ARG_HEIGHT);
gtk_object_add_arg_type("GstEditorElement::x1",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_X1);
gtk_object_add_arg_type("GstEditorElement::y1",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_Y1);
gtk_object_add_arg_type("GstEditorElement::x2",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_X2);
gtk_object_add_arg_type("GstEditorElement::y2",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_Y2);
gtk_object_add_arg_type("GstEditorElement::element",GTK_TYPE_POINTER,
GTK_ARG_READABLE,ARG_ELEMENT);
klass->realize = gst_editor_element_realize;
klass->event = gst_editor_element_event;
object_class->set_arg = gst_editor_element_set_arg;
object_class->get_arg = gst_editor_element_get_arg;
}
static void gst_editor_element_init(GstEditorElement *element) {
}
GstEditorElement *gst_editor_element_new(GstEditorBin *parent,
GstElement *element,
const gchar *first_arg_name, ...) {
GstEditorElement *editorelement;
va_list args;
g_return_if_fail(parent != NULL);
g_return_if_fail(GST_IS_EDITOR_BIN(parent));
g_return_if_fail(element != NULL);
g_return_if_fail(GST_IS_ELEMENT(element));
editorelement = GST_EDITOR_ELEMENT(gtk_type_new(GST_TYPE_EDITOR_ELEMENT));
editorelement->element = element;
va_start(args,first_arg_name);
gst_editor_element_construct(editorelement,parent,first_arg_name,args);
va_end(args);
return editorelement;
}
void gst_editor_element_construct(GstEditorElement *element,
GstEditorBin *parent,
const gchar *first_arg_name,
va_list args) {
GtkObject *obj = GTK_OBJECT(element);
GSList *arg_list = NULL, *info_list = NULL;
gchar *error;
GstEditorElementClass *elementclass;
// g_print("in gst_editor_element_construct()\n");
error = gtk_object_args_collect(GTK_OBJECT_TYPE(obj),&arg_list,
&info_list,first_arg_name,args);
if (error) {
g_warning("gst_editor_element_construct(): %s",error);
g_free(error);
} else {
GSList *arg,*info;
// g_print("setting all the arguments on the element\n");
for (arg=arg_list,info=info_list;arg;arg=arg->next,info=info->next)
gtk_object_arg_set(obj,arg->data,info->data);
gtk_args_collect_cleanup(arg_list,info_list);
}
if (parent)
gst_editor_bin_add(parent,element);
else if (!GST_IS_EDITOR_BIN(element))
g_warning("floating element...\n");
elementclass = GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass);
if (elementclass->realize)
(elementclass->realize)(element);
}
static void gst_editor_element_set_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditorElement *element;
gdouble dx,dy,newwidth,newheight;
/* get the major types of this object */
element = GST_EDITOR_ELEMENT(object);
switch (id) {
case ARG_X:
element->x = GTK_VALUE_DOUBLE(*arg);
break;
case ARG_Y:
element->y = GTK_VALUE_DOUBLE(*arg);
break;
case ARG_WIDTH:
element->width = GTK_VALUE_DOUBLE(*arg);
element->resize = TRUE;
break;
case ARG_HEIGHT:
element->height = GTK_VALUE_DOUBLE(*arg);
element->resize = TRUE;
break;
case ARG_X1:
element->x = GTK_VALUE_DOUBLE(*arg);
element->resize = TRUE;
break;
case ARG_Y1:
element->y = GTK_VALUE_DOUBLE(*arg);
element->resize = TRUE;
break;
case ARG_X2:
// make sure it's big enough, grow if not
element->width = MAX(GTK_VALUE_DOUBLE(*arg),element->minwidth);
element->resize = TRUE;
break;
case ARG_Y2:
// make sure it's big enough, grow if not
element->height = MAX(GTK_VALUE_DOUBLE(*arg),element->minheight);
element->resize = TRUE;
break;
default:
g_warning("gsteditorelement: unknown arg!");
break;
}
}
static void gst_editor_element_get_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditorElement *element;
/* get the major types of this object */
element = GST_EDITOR_ELEMENT(object);
switch (id) {
case ARG_X:
GTK_VALUE_INT(*arg) = element->x + (element->width / 2.0);
break;
case ARG_Y:
GTK_VALUE_INT(*arg) = element->y + (element->height / 2.0);
break;
case ARG_WIDTH:
GTK_VALUE_INT(*arg) = element->width;
break;
case ARG_HEIGHT:
GTK_VALUE_INT(*arg) = element->height;
break;
case ARG_X1:
GTK_VALUE_INT(*arg) = element->x;
break;
case ARG_Y1:
GTK_VALUE_INT(*arg) = element->y;
break;
case ARG_X2:
GTK_VALUE_INT(*arg) = element->x + element->width;
break;
case ARG_Y2:
GTK_VALUE_INT(*arg) = element->y + element->height;
break;
case ARG_ELEMENT:
GTK_VALUE_POINTER(*arg) = element->element;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
static void gst_editor_element_realize(GstEditorElement *element) {
GnomeCanvasGroup *parentgroup;
gint i;
gdouble x1,y1,x2,y2;
GList *pads;
GstPad *pad;
// g_print("realizing editor element %p\n",element);
/* we have to have a parent by this point */
g_return_if_fail(element->parent != NULL);
// set the state signal of the actual element
gtk_signal_connect(GTK_OBJECT(element->element),"state_change",
GTK_SIGNAL_FUNC(gst_editor_element_state_change),
element);
// create the bounds if we haven't had them set
// g_print("centering element at %.2fx%.2f (%.2fx%.2f)\n",
// element->x,element->y,element->width,element->height);
/* create the group holding all the stuff for this element */
parentgroup = GST_EDITOR_ELEMENT(element->parent)->group;
element->group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(parentgroup,
gnome_canvas_group_get_type(),
"x",element->x - (element->width / 2.0),
"y",element->y - (element->height / 2.0),NULL));
// g_print("origin of group is %.2fx%.2f\n",
// element->x - (element->width / 2.0),
// element->y - (element->height / 2.0));
g_return_if_fail(element->group != NULL);
GST_EDITOR_SET_OBJECT(element->group,element);
gtk_signal_connect(GTK_OBJECT(element->group),"event",
GTK_SIGNAL_FUNC(gst_editor_element_group_event),element);
// calculate the inter-group coords (x1,y1,x2,y2 are convenience vars)
x1 = 0.0;y1 = 0.0;
x2 = element->width;y2 = element->height;
/* create bordering box */
element->border = gnome_canvas_item_new(element->group,
gnome_canvas_rect_get_type(),
"width_units",2.0,"fill_color","white","outline_color","black",
"x1",x1,"y1",y1,"x2",x2,"y2",y2,NULL);
g_return_if_fail(element->border != NULL);
GST_EDITOR_SET_OBJECT(element->border,element);
/* create resizing box */
element->resizebox = gnome_canvas_item_new(element->group,
gnome_canvas_rect_get_type(),
"width_units",1.0,"fill_color","white","outline_color","black",
"x1",x2-4.0,"y1",y2-4.0,"x2",x2,"y2",y2,NULL);
g_return_if_fail(element->resizebox != NULL);
GST_EDITOR_SET_OBJECT(element->resizebox,element);
gtk_signal_connect(GTK_OBJECT(element->resizebox),"event",
GTK_SIGNAL_FUNC(gst_editor_element_resizebox_event),element);
/* create the title */
element->title = gnome_canvas_item_new(element->group,
gnome_canvas_text_get_type(),
"text",gst_element_get_name(GST_OBJECT(element->element)),
"x",x1+1.0,"y",y1+1.0,"anchor",GTK_ANCHOR_NORTH_WEST,
"font_gdk",gtk_widget_get_default_style()->font,
NULL);
g_return_if_fail(element->title != NULL);
GST_EDITOR_SET_OBJECT(element->title,element);
/* create the state boxen */
for (i=0;i<4;i++) {
element->statebox[i] = gnome_canvas_item_new(element->group,
gnome_canvas_rect_get_type(),
"width_units",1.0,"fill_color","white","outline_color","black",
"x1",0.0,"y1",0.0,"x2",0.0,"y2",0.0,
NULL);
g_return_if_fail(element->statebox[i] != NULL);
GST_EDITOR_SET_OBJECT(element->statebox[i],element);
gtk_signal_connect(GTK_OBJECT(element->statebox[i]),"event",
GTK_SIGNAL_FUNC(gst_editor_element_state_event),
GINT_TO_POINTER(i));
element->statetext[i] = gnome_canvas_item_new(element->group,
gnome_canvas_text_get_type(),
"text",_gst_editor_element_states[i],
"x",0.0,"y",0.0,"anchor",GTK_ANCHOR_NORTH_WEST,
"font","-*-*-*-*-*-*-6-*-*-*-*-*-*-*",
NULL);
g_return_if_fail(element->statetext[i] != NULL);
GST_EDITOR_SET_OBJECT(element->statetext[i],element);
gtk_signal_connect(GTK_OBJECT(element->statetext[i]),"event",
GTK_SIGNAL_FUNC(gst_editor_element_state_event),
GINT_TO_POINTER(i));
}
/* and the play box (FIXME: should be icons, not text */
element->playbox = gnome_canvas_item_new(element->group,
gnome_canvas_rect_get_type(),
"width_units",1.0,"fill_color","white","outline_color","black",
"x1",0.0,"y1",0.0,"x2",0.0,"y2",0.0,
NULL);
g_return_if_fail(element->playbox != NULL);
GST_EDITOR_SET_OBJECT(element->playbox,element);
gtk_signal_connect(GTK_OBJECT(element->playbox),"event",
GTK_SIGNAL_FUNC(gst_editor_element_state_event),
GINT_TO_POINTER(4));
element->playtext = gnome_canvas_item_new(element->group,
gnome_canvas_text_get_type(),
"text","P",
"x",0.0,"y",0.0,"anchor",GTK_ANCHOR_NORTH_WEST,
"font","-*-*-*-*-*-*-6-*-*-*-*-*-*-*",
NULL);
g_return_if_fail(element->playtext != NULL);
GST_EDITOR_SET_OBJECT(element->playtext,element);
gtk_signal_connect(GTK_OBJECT(element->playtext),"event",
GTK_SIGNAL_FUNC(gst_editor_element_state_event),
GINT_TO_POINTER(4));
// get all the pads
pads = gst_element_get_pad_list(element->element);
while (pads) {
pad = GST_PAD(pads->data);
gst_editor_element_add_pad(element,pad);
pads = g_list_next(pads);
}
element->realized = TRUE;
// force a resize
element->resize = TRUE;
gst_editor_element_resize(element);
// recenter things on the supposed center
// g_print("recentering element at %.2fx%.2f (%.2fx%.2f)\n",
// element->x,element->y,element->width,element->height);
element->x -= (element->width / 2.0);
element->y -= (element->height / 2.0);
gnome_canvas_item_set(GNOME_CANVAS_ITEM(element->group),
"x",element->x,"y",element->y,NULL);
// g_print("origin of group is %.2fx%.2f\n",element->x,element->y);
gst_editor_element_repack(element);
}
static void gst_editor_element_resize(GstEditorElement *element) {
gdouble itemwidth,itemheight;
gdouble groupwidth,groupheight;
GList *pads;
GstEditorPad *editorpad;
gint i;
if (element->resize != TRUE) return;
element->resize = FALSE;
// g_print("resizing element\n");
element->minwidth = element->insidewidth;
element->minheight = element->insideheight;
// get the text size and add it into minsize
g_return_if_fail(element->title != NULL);
itemwidth = gst_util_get_double_arg(GTK_OBJECT(element->title),
"text_width") + 2.0;
itemheight = gst_util_get_double_arg(GTK_OBJECT(element->title),
"text_height") + 2.0;
element->titlewidth = itemwidth;
element->titleheight = itemheight;
element->minwidth = MAX(element->minwidth,itemwidth);
element->minheight += itemheight;
// now do the bottom bar
// find the biggest of the state chars
element->statewidth = 0.0;element->stateheight = 0.0;
for (i=0;i<4;i++) {
g_return_if_fail(element->statetext[i] != NULL);
itemwidth = gst_util_get_double_arg(GTK_OBJECT(element->statetext[i]),
"text_width") - 2.0;
itemwidth = gst_util_get_double_arg(GTK_OBJECT(element->statetext[i]),
"text_height");
element->statewidth = MAX(element->statewidth,itemwidth);
element->stateheight = MAX(element->stateheight,itemheight);
}
// calculate the size of the primary group
groupwidth = element->statewidth * 5; // 4 states plus playstate
groupheight = element->stateheight;
// add in the resize box
groupwidth += 7.0; // 2.0 for buffer, 5.0 for actual size
groupheight = MAX(groupheight,5.0);
// update the minsize
element->minwidth = MAX(element->minwidth,groupwidth);
element->minheight += groupheight;
// now go and try to calculate necessary space for the pads
element->sinkwidth = 10.0;element->sinkheight = 0.0;element->sinks = 0;
pads = element->sinkpads;
while (pads) {
editorpad = GST_EDITOR_PAD(pads->data);
element->sinkwidth = MAX(element->sinkwidth,editorpad->width);
element->sinkheight = MAX(element->sinkheight,editorpad->height);
element->sinks++;
pads = g_list_next(pads);
}
element->srcwidth = 10.0;element->srcheight = 0.0;element->srcs = 0;
pads = element->srcpads;
while (pads) {
editorpad = GST_EDITOR_PAD(pads->data);
element->srcwidth = MAX(element->srcwidth,editorpad->width);
element->srcheight = MAX(element->srcheight,editorpad->height);
element->srcs++;
pads = g_list_next(pads);
}
// add in the needed space
element->minheight += MAX((element->sinkheight*element->sinks),
(element->srcheight*element->srcs)) + 4.0;
element->minwidth = MAX(element->minwidth,
((element->sinkwidth*element->sinks) +
(element->srcwidth*element->srcs) + 4.0));
// g_print("have %d sinks (%.2fx%.2f) and %d srcs (%.2fx%.2f)\n",
// element->sinks,element->sinkwidth,element->sinkheight,
// element->srcs,element->srcwidth,element->srcheight);
// grow the element to hold all the stuff
// g_print("minsize is %.2fx%.2f,
//",element->minwidth,element->minheight);
// g_print("size was %.2fx%.2f, ",element->width,element->height);
element->width = MAX(element->width,element->minwidth);
element->height = MAX(element->height,element->minheight);
// g_print("is now %.2fx%.2f\n",element->width,element->height);
}
void gst_editor_element_repack(GstEditorElement *element) {
GList *pads;
GstPad *pad;
GstEditorPad *editorpad;
gdouble sinkwidth,sinkheight;
gint sinks;
gdouble srcwidth,srcheight;
gint srcs;
gdouble x1,y1,x2,y2;
gint i;
if (!element->realized) return;
gst_editor_element_resize(element);
// still use x1,y1,x2,y2 so we can change around later
x1 = 0.0;y1 = 0.0;
x2 = element->width;y2 = element->height;
// g_print("repacking element at %.2fx%.2f + %.2fx%.2f\n",
// element->x,element->y,x2,y2);
// move the element group to match
gnome_canvas_item_set(GNOME_CANVAS_ITEM(element->group),
"x",element->x,"y",element->y,NULL);
// start by resizing the bordering box
g_return_if_fail(element->border != NULL);
gtk_object_set(GTK_OBJECT(element->border),
"x1",x1,"y1",y1,"x2",x2,"y2",y2,NULL);
// then move the text to the new top left
g_return_if_fail(element->title != NULL);
gtk_object_set(GTK_OBJECT(element->title),
"x",x1+1.0,"y",y1+1.0,
"anchor",GTK_ANCHOR_NORTH_WEST,
NULL);
// and move the resize box
g_return_if_fail(element->resizebox != NULL);
gtk_object_set(GTK_OBJECT(element->resizebox),
"x1",x2-5.0,"y1",y2-5.0,"x2",x2,"y2",y2,NULL);
// now place the state boxes
for (i=0;i<4;i++) {
g_return_if_fail(element->statebox[i] != NULL);
gtk_object_set(GTK_OBJECT(element->statebox[i]),
"x1",x1+(element->statewidth*i),
"y1",y2-element->stateheight,
"x2",x1+(element->statewidth*(i+1)),"y2",y2,NULL);
g_return_if_fail(element->statetext[i] != NULL);
gtk_object_set(GTK_OBJECT(element->statetext[i]),
"x",x1+(element->statewidth*i)+2.0,
"y",y2-element->stateheight+1.0,
"anchor",GTK_ANCHOR_NORTH_WEST,NULL);
}
// and the playstate box
g_return_if_fail(element->playbox != NULL);
gtk_object_set(GTK_OBJECT(element->playbox),
"x1",x1+(element->statewidth*4),
"y1",y2-element->stateheight,
"x2",x1+(element->statewidth*5),"y2",y2,NULL);
g_return_if_fail(element->playtext != NULL);
gtk_object_set(GTK_OBJECT(element->playtext),
"x",x1+(element->statewidth*4)+2.0,
"y",y2-element->stateheight+1.0,
"anchor",GTK_ANCHOR_NORTH_WEST,NULL);
// now we try to place all the pads
sinks = element->sinks;
pads = element->sinkpads;
while (pads) {
editorpad = GST_EDITOR_PAD(pads->data);
gtk_object_set(GTK_OBJECT(editorpad),
"x",x1,
"y",y2 - 2.0 - element->stateheight -
(element->sinkheight * sinks),
NULL);
gst_editor_pad_repack(editorpad);
sinks--;
pads = g_list_next(pads);
}
srcs = element->srcs;
pads = element->srcpads;
while (pads) {
editorpad = GST_EDITOR_PAD(pads->data);
gtk_object_set(GTK_OBJECT(editorpad),
"x",x2 - element->srcwidth,
"y",y2 - 2.0 - element->stateheight -
(element->srcheight * srcs),
NULL);
gst_editor_pad_repack(editorpad);
srcs--;
pads = g_list_next(pads);
}
// g_print("done resizing element\n");
}
GstEditorPad *gst_editor_element_add_pad(GstEditorElement *element,
GstPad *pad) {
GstEditorPad *editorpad;
editorpad = gst_editor_pad_new(element,pad,NULL);
if (pad->direction == GST_PAD_SINK) {
element->sinkpads = g_list_prepend(element->sinkpads,editorpad);
element->sinks++;
// g_print("added 'new' pad to sink list\n");
} else if (pad->direction == GST_PAD_SRC) {
element->srcpads = g_list_prepend(element->srcpads,editorpad);
element->srcs++;
// g_print("added 'new' pad to src list\n");
} else
g_print("HUH?!? Don't know which direction this pad is...\n");
element->padlistchange = TRUE;
gst_editor_element_repack(element);
return editorpad;
}
static gint gst_editor_element_group_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element) {
// g_print("in group_event, type %d\n",event->type);
if (GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass)->event)
return (GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass)->event)(
item,event,element);
return FALSE;
}
static gint gst_editor_element_event(GnomeCanvasItem *item,GdkEvent *event,
GstEditorElement *element) {
gdouble item_x,item_y,dx,dy;
GdkCursor *fleur;
// g_print("element in event, type %d\n",event->type);
switch(event->type) {
case GDK_ENTER_NOTIFY:
break;
case GDK_LEAVE_NOTIFY:
break;
case GDK_BUTTON_PRESS:
// dragxy coords are world coords of button press
element->dragx = event->button.x;
element->dragy = event->button.y;
// set some flags
element->dragging = TRUE;
element->moved = FALSE;
fleur = gdk_cursor_new(GDK_FLEUR);
gnome_canvas_item_grab(item,
GDK_POINTER_MOTION_MASK |
// GDK_ENTER_NOTIFY_MASK |
// GDK_LEAVE_NOTIFY_MASK |
GDK_BUTTON_RELEASE_MASK,
fleur,event->button.time);
return TRUE;
break;
case GDK_MOTION_NOTIFY:
if (element->dragging) {
dx = event->button.x - element->dragx;
dy = event->button.y - element->dragy;
gst_editor_element_move(element,dx,dy);
element->dragx = event->button.x;
element->dragy = event->button.y;
element->moved = TRUE;
}
return TRUE;
break;
case GDK_BUTTON_RELEASE:
if (element->dragging) {
element->dragging = FALSE;
gnome_canvas_item_ungrab(item,event->button.time);
}
if (!element->moved) {
GstEditorElementClass *elementclass;
elementclass = GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass);
if (elementclass->button_event)
(elementclass->button_event)(item,event,element);
}
//g_print("in element group_event, setting inchild");
element->canvas->inchild = TRUE;
return TRUE;
break;
default:
break;
}
return FALSE;
}
static gint gst_editor_element_resizebox_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorElement *element) {
GdkCursor *bottomright;
gdouble item_x,item_y;
// g_print("in resizebox_event...\n");
// calculate coords relative to the group, not the box
item_x = event->button.x;
item_y = event->button.y;
gnome_canvas_item_w2i(item->parent,&item_x,&item_y);
switch(event->type) {
case GDK_ENTER_NOTIFY:
break;
case GDK_LEAVE_NOTIFY:
element->hesitating = FALSE;
break;
case GDK_BUTTON_PRESS:
element->dragx = event->button.x;
element->dragy = event->button.y;
element->resizing = TRUE;
element->hesitating = TRUE;
bottomright = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER);
gnome_canvas_item_grab(item,
GDK_POINTER_MOTION_MASK |
GDK_ENTER_NOTIFY_MASK |
GDK_LEAVE_NOTIFY_MASK |
GDK_BUTTON_RELEASE_MASK,
bottomright,event->button.time);
return TRUE;
break;
case GDK_MOTION_NOTIFY:
if (element->resizing) {
// doing a set because the code is in the arg set code
// g_print("resizing to x2,y2 of %.2f,%.2f\n",item_x,item_y);
gtk_object_set(GTK_OBJECT(element),"x2",item_x,"y2",item_y,NULL);
element->resize = TRUE;
gst_editor_element_repack(element);
return TRUE;
}
break;
case GDK_BUTTON_RELEASE:
if (element->resizing) {
element->resizing = FALSE;
gnome_canvas_item_ungrab(item,event->button.time);
//g_print("in element resizebox_event, setting inchild");
element->canvas->inchild = TRUE;
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
static gint gst_editor_element_state_event(GnomeCanvasItem *item,
GdkEvent *event,
gpointer data) {
GstEditorElement *element;
gint id = GPOINTER_TO_INT(data);
GdkCursor *uparrow;
element = GST_EDTIOR_GET_OBJECT(item);
switch (event->type) {
case GDK_ENTER_NOTIFY:
uparrow = gdk_cursor_new(GDK_SB_UP_ARROW);
gnome_canvas_item_grab(item,
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_LEAVE_NOTIFY_MASK,
uparrow,event->button.time);
/* NOTE: when grabbing canvas item, always get pointer_motion,
this will allow you to actually get all the other synth events */
break;
case GDK_LEAVE_NOTIFY:
gnome_canvas_item_ungrab(item,event->button.time);
break;
case GDK_BUTTON_PRESS:
return TRUE;
break;
case GDK_BUTTON_RELEASE:
if (id < 5) {
element->states[id] = !element->states[id];
gst_editor_element_set_state(element,id,TRUE);
} else
g_warning("Uh, shouldn't have gotten here, unknown state\n");
//g_print("in element statebox_event, setting inchild");
element->canvas->inchild = TRUE;
return TRUE;
break;
default:
break;
}
return FALSE;
}
static void gst_editor_element_set_state(GstEditorElement *element,
gint id,gboolean set) {
gboolean stateset = TRUE; /* if we have no element, set anyway */
if (element->states[id]) {
/* set the object state */
if (set && element->element)
stateset = gst_element_set_state(element->element,(1 << id));
/* change the display */
if (stateset) {
if (id < 4) {
gtk_object_set(GTK_OBJECT(element->statebox[id]),
"fill_color","black",NULL);
gtk_object_set(GTK_OBJECT(element->statetext[id]),
"fill_color","white",NULL);
} else if (id == 4) {
gtk_object_set(GTK_OBJECT(element->playbox),
"fill_color","black",NULL);
gtk_object_set(GTK_OBJECT(element->playtext),
"fill_color","white",NULL);
}
} else {
g_print("error setting state %d\n",id);
element->states[id] = !element->states[id];
}
} else {
if (set && element->element)
stateset = gst_element_set_state(element->element,~(1 << id));
if (stateset) {
if (id < 4) {
gtk_object_set(GTK_OBJECT(element->statebox[id]),
"fill_color","white",NULL);
gtk_object_set(GTK_OBJECT(element->statetext[id]),
"fill_color","black",NULL);
} else if (id == 4) {
gtk_object_set(GTK_OBJECT(element->playbox),
"fill_color","white",NULL);
gtk_object_set(GTK_OBJECT(element->playtext),
"fill_color","black",NULL);
}
} else {
g_print("error unsetting state %d\n",id);
element->states[id] = !element->states[id];
}
}
}
static void gst_editor_element_state_change(GstElement *element,
gint state,
GstEditorElement *editorelement) {
gint id;
g_return_if_fail(editorelement != NULL);
// g_print("gst_editor_element_state_change got state 0x%08x\n",state);
// if it's an unset
if (state & GST_STATE_MAX) {
state = ~state;
for (id=0;id<(sizeof(state)*8)-1;id++) {
if (state & 1) {
editorelement->states[id] = FALSE;
break;
}
state /= 2;
}
} else {
for (id=0;id<(sizeof(state)*8)-1;id++) {
if (state & 1) {
editorelement->states[id] = TRUE;
break;
}
state /= 2;
}
}
gst_editor_element_set_state(editorelement,id,FALSE);
}
static void gst_editor_element_sync_state(GstEditorElement *element) {
gint id;
// g_print("syncronizing state\n");
for (id=0;id<5;id++) {
element->states[id] = GST_FLAG_IS_SET(element->element,1<<id);
gst_editor_element_set_state(element,id,FALSE);
}
}
static void gst_editor_element_move(GstEditorElement *element,
gdouble dx,gdouble dy) {
GList *pads;
GstEditorPad *pad;
// this is a 'little' trick to keep from repacking the whole thing...
element->x += dx;element->y += dy;
gnome_canvas_item_move(GNOME_CANVAS_ITEM(element->group),dx,dy);
pads = element->srcpads;
while (pads) {
pad = GST_EDITOR_PAD(pads->data);
if (pad->connection) {
// g_print("updating pad's connection\n");
pad->connection->resize = TRUE;
gst_editor_connection_resize(pad->connection);
}
pads = g_list_next(pads);
}
pads = element->sinkpads;
while (pads) {
pad = GST_EDITOR_PAD(pads->data);
if (pad->connection) {
// g_print("updating pad's connection\n");
pad->connection->resize = TRUE;
gst_editor_connection_resize(pad->connection);
}
pads = g_list_next(pads);
}
}

406
editor/gsteditorpad.c Normal file
View file

@ -0,0 +1,406 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gnome.h>
#include <gst/gst.h>
#include "gsteditor.h"
/* class functions */
static void gst_editor_pad_class_init(GstEditorPadClass *klass);
static void gst_editor_pad_init(GstEditorPad *pad);
static void gst_editor_pad_set_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_pad_get_arg(GtkObject *object,GtkArg *arg,guint id);
static void gst_editor_pad_realize(GstEditorPad *pad);
/* class implementation functions */
static void gst_editor_pad_update(GnomeCanvasItem *item,double *affine,
ArtSVP *clip_path,int flags);
static gint gst_editor_pad_event(GnomeCanvasItem *item,GdkEvent *event);
/* events fired by items within self */
static gint gst_editor_pad_padbox_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorPad *pad);
/* utility functions */
static void gst_editor_pad_resize(GstEditorPad *pad);
enum {
ARG_0,
ARG_X,
ARG_Y,
ARG_WIDTH,
ARG_HEIGHT,
ARG_PAD,
};
enum {
LAST_SIGNAL
};
static GtkObjectClass *parent_class;
static guint gst_editor_pad_signals[LAST_SIGNAL] = { 0 };
GtkType gst_editor_pad_get_type() {
static GtkType pad_type = 0;
if (!pad_type) {
static const GtkTypeInfo pad_info = {
"GstEditorPad",
sizeof(GstEditorPad),
sizeof(GstEditorPadClass),
(GtkClassInitFunc)gst_editor_pad_class_init,
(GtkObjectInitFunc)gst_editor_pad_init,
NULL,
NULL,
(GtkClassInitFunc)NULL,
};
pad_type = gtk_type_unique(gtk_object_get_type(),&pad_info);
}
return pad_type;
}
static void gst_editor_pad_class_init(GstEditorPadClass *klass) {
GtkObjectClass *object_class;
object_class = (GtkObjectClass*)klass;
parent_class = gtk_type_class(gtk_object_get_type());
gtk_object_add_arg_type("GstEditorPad::x",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_X);
gtk_object_add_arg_type("GstEditorPad::y",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_Y);
gtk_object_add_arg_type("GstEditorPad::width",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_WIDTH);
gtk_object_add_arg_type("GstEditorPad::height",GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE,ARG_HEIGHT);
gtk_object_add_arg_type("GstEditorPad::pad",GTK_TYPE_POINTER,
GTK_ARG_READWRITE,ARG_PAD);
klass->realize = gst_editor_pad_realize;
object_class->set_arg = gst_editor_pad_set_arg;
object_class->get_arg = gst_editor_pad_get_arg;
}
static void gst_editor_pad_init(GstEditorPad *pad) {
}
GstEditorPad *gst_editor_pad_new(GstEditorElement *parent,GstPad *pad,
const gchar *first_arg_name, ...) {
GstEditorPad *editorpad;
va_list args;
g_return_if_fail(parent != NULL);
g_return_if_fail(GST_IS_EDITOR_ELEMENT(parent));
g_return_if_fail(pad != NULL);
g_return_if_fail(GST_IS_PAD(pad));
editorpad = GST_EDITOR_PAD(gtk_type_new(GST_TYPE_EDITOR_PAD));
editorpad->pad = pad;
va_start(args,first_arg_name);
gst_editor_pad_construct(editorpad,parent,first_arg_name,args);
va_end(args);
return editorpad;
}
void gst_editor_pad_construct(GstEditorPad *pad,
GstEditorElement *parent,
const gchar *first_arg_name,va_list args) {
GtkObject *obj = GTK_OBJECT(pad);
GSList *arg_list = NULL, *info_list = NULL;
gchar *error;
GstEditorPadClass *padclass;
// g_print("in gst_editor_pad_construct()\n");
error = gtk_object_args_collect(GTK_OBJECT_TYPE(obj),&arg_list,
&info_list,first_arg_name,args);
if (error) {
g_warning("gst_editor_pad_construct(): %s",error);
g_free(error);
} else {
GSList *arg,*info;
// g_print("setting all the arguments on the pad\n");
for (arg=arg_list,info=info_list;arg;arg=arg->next,info=info->next)
gtk_object_arg_set(obj,arg->data,info->data);
gtk_args_collect_cleanup(arg_list,info_list);
}
pad->parent = parent;
padclass = GST_EDITOR_PAD_CLASS(GTK_OBJECT(pad)->klass);
if (padclass)
(padclass->realize)(pad);
}
static void gst_editor_pad_set_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditorPad *pad;
/* get the major types of this object */
pad = GST_EDITOR_PAD(object);
switch (id) {
case ARG_X:
pad->x = GTK_VALUE_DOUBLE(*arg);
break;
case ARG_Y:
pad->y = GTK_VALUE_DOUBLE(*arg);
break;
case ARG_WIDTH:
pad->width = GTK_VALUE_DOUBLE(*arg);
pad->resize = TRUE;
break;
case ARG_HEIGHT:
pad->height = GTK_VALUE_DOUBLE(*arg);
pad->resize = TRUE;
break;
case ARG_PAD:
/* FIXME: this is very brute force */
pad->pad = GTK_VALUE_POINTER(*arg);
break;
default:
g_warning("gsteditorpad: unknown arg!");
break;
}
}
static void gst_editor_pad_get_arg(GtkObject *object,GtkArg *arg,guint id) {
GstEditorPad *pad;
/* get the major types of this object */
pad = GST_EDITOR_PAD(object);
switch (id) {
case ARG_X:
GTK_VALUE_INT(*arg) = pad->x;
break;
case ARG_Y:
GTK_VALUE_INT(*arg) = pad->y;
break;
case ARG_WIDTH:
GTK_VALUE_INT(*arg) = pad->width;
break;
case ARG_HEIGHT:
GTK_VALUE_INT(*arg) = pad->height;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
static void gst_editor_pad_realize(GstEditorPad *pad) {
gint i;
// g_print("realizing editor pad %p\n",pad);
/* we must be attached to an element */
g_return_if_fail(pad->parent != NULL);
/* create the group and bounding box */
pad->group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(pad->parent->group,
gnome_canvas_group_get_type(),"x",pad->x,"y",pad->y,NULL));
g_return_if_fail(pad->group != NULL);
GST_EDITOR_SET_OBJECT(pad->group,pad);
pad->border = gnome_canvas_item_new(pad->group,
gnome_canvas_rect_get_type(),
"width_units",1.0,"fill_color","white","outline_color","black",
"x1",0.0,"y1",0.0,"x2",pad->width,"y2",pad->height,NULL);
g_return_if_fail(pad->border != NULL);
GST_EDITOR_SET_OBJECT(pad->border,pad);
/* create the pad box on the correct side */
pad->issrc = (pad->pad->direction == GST_PAD_SRC);
if (pad->issrc)
pad->padbox = gnome_canvas_item_new(pad->group,
gnome_canvas_rect_get_type(),
"width_units",1.0,"fill_color","white","outline_color","black",
"x1",pad->x-4.0,"y1",2.0,"x2",pad->x,"y2",pad->height-2.0,NULL);
else
pad->padbox = gnome_canvas_item_new(pad->group,
gnome_canvas_rect_get_type(),
"width_units",1.0,"fill_color","white","outline_color","black",
"x1",0.0,"y1",2.0,"x2",4.0,"y2",pad->height-2.0,NULL);
g_return_if_fail(pad->padbox != NULL);
GST_EDITOR_SET_OBJECT(pad->padbox,pad);
gtk_signal_connect(GTK_OBJECT(pad->padbox),"event",
GTK_SIGNAL_FUNC(gst_editor_pad_padbox_event),pad);
pad->title = gnome_canvas_item_new(pad->group,
gnome_canvas_text_get_type(),
"text",gst_pad_get_name(pad->pad),
"x",0.0,"y",0.0,"anchor",GTK_ANCHOR_NORTH_WEST,
"font_gdk",gtk_widget_get_default_style()->font,
NULL);
g_return_if_fail(pad->title != NULL);
GST_EDITOR_SET_OBJECT(pad->title,pad);
pad->realized = TRUE;
pad->resize = TRUE;
gst_editor_pad_repack(pad);
}
static void gst_editor_pad_resize(GstEditorPad *pad) {
gdouble minwidth,minheight;
// g_print("resizing pad\n");
minwidth = 0;minheight = 0;
/* get the text size and add it into minsize */
minwidth = gst_util_get_double_arg(GTK_OBJECT(pad->title),
"text_width") + 2.0;
minheight = gst_util_get_double_arg(GTK_OBJECT(pad->title),
"text_height");
/* calculate the size of the padbox */
pad->boxheight = minheight - 4.0;
pad->boxwidth = pad->boxheight / 2.0;
minwidth += pad->boxwidth;
/* force the thing to grow if necessary */
pad->width = MAX(pad->width,minwidth);
pad->height = MAX(pad->height,minheight);
/* update the connection if there is one */
// g_print("connection is %p\n",pad->connection);
if (pad->connection != NULL)
gst_editor_connection_resize(pad->connection);
}
void gst_editor_pad_repack(GstEditorPad *pad) {
gdouble x1,y1,x2,y2;
if (!pad->realized) return;
gst_editor_pad_resize(pad);
x1 = 0;y1 = 0;
x2 = x1 + pad->width;y2 = y1 + pad->height;
// g_print("repacking pad at %.2fx%.2f - %.2fx%.2f\n",x1,y1,x2,y2);
/* move the group */
gtk_object_set(GTK_OBJECT(pad->group),"x",pad->x,"y",pad->y,NULL);
/* start by resizing the bordering box */
gtk_object_set(GTK_OBJECT(pad->border),
"x1",x1,"y1",y1,"x2",x2,"y2",y2,NULL);
/* if we're a left-jusified sink */
if (pad->issrc) {
/* and move the pad box */
gtk_object_set(GTK_OBJECT(pad->padbox),
"x1",x2-pad->boxwidth,"y1",y1+2.0,
"x2",x2,"y2",y2-2.0,NULL);
/* then move the text to the right place */
gtk_object_set(GTK_OBJECT(pad->title),
"x",x2-pad->boxwidth-1.0,"y",y1,
"anchor",GTK_ANCHOR_NORTH_EAST,
NULL);
} else {
/* and move the pad box */
gtk_object_set(GTK_OBJECT(pad->padbox),
"x1",x1,"y1",y1+2.0,
"x2",x1+pad->boxwidth,"y2",y2-2.0,NULL);
/* then move the text to the right place */
gtk_object_set(GTK_OBJECT(pad->title),
"x",x1+pad->boxwidth+1.0,"y",y1,
"anchor",GTK_ANCHOR_NORTH_WEST,
NULL);
}
if (pad->connection != NULL) {
pad->connection->resize = TRUE;
gst_editor_connection_resize(pad->connection);
}
pad->resize = FALSE;
}
/*
static gint gst_editor_pad_event(GnomeCanvasItem *item,GdkEvent *event) {
GstEditorPad *pad = GST_EDITOR_PAD(item);
gdouble item_x,item_y;
GdkCursor *fleur;
gdouble tx,ty;
item_x = event->button.x;
item_y = event->button.y;
gnome_canvas_item_w2i(item->parent,&item_x,&item_y);
switch(event->type) {
case GDK_ENTER_NOTIFY:
// g_print("entered pad\n");
break;
case GDK_LEAVE_NOTIFY:
// g_print("left pad\n");
break;
default:
break;
}
return FALSE;
}
*/
/* FIXME FIXME FIXME */
static gint gst_editor_pad_padbox_event(GnomeCanvasItem *item,
GdkEvent *event,
GstEditorPad *pad) {
GstEditorElement *element;
GstEditorBin *bin;
// g_print("padbox has event %d\n",event->type);
g_return_if_fail(GST_IS_EDITOR_PAD(pad));
element = pad->parent;
bin = element->parent;
switch(event->type) {
case GDK_ENTER_NOTIFY:
// g_print("entered pad '%s'\n",
// gst_pad_get_name(pad->pad));
break;
case GDK_LEAVE_NOTIFY:
// g_print("left pad '%s'\n",
// gst_pad_get_name(pad->pad));
break;
case GDK_BUTTON_PRESS:
// g_print("have button press in pad '%s'\n",
// gst_pad_get_name(pad->pad));
gst_editor_bin_start_banding(bin,pad);
return TRUE;
break;
case GDK_MOTION_NOTIFY:
// g_print("have motion in pad\n");
break;
default:
break;
}
return FALSE;
}

79
editor/gsteditorpad.h Normal file
View file

@ -0,0 +1,79 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_EDITOR_PAD_H__
#define __GST_EDITOR_PAD_H__
#include <gst/gst.h>
#define GST_TYPE_EDITOR_PAD \
(gst_editor_pad_get_type())
#define GST_EDITOR_PAD(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_PAD,GstEditorPad))
#define GST_EDITOR_PAD_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_PAD,GstEditorPad))
#define GST_IS_EDITOR_PAD(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_PAD))
#define GST_IS_EDITOR_PAD_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_PAD)))
typedef struct _GstEditorPad GstEditorPad;
typedef struct _GstEditorPadClass GstEditorPadClass;
struct _GstEditorPad {
GtkObject object;
/* parent object */
GtkObject *parent; // FIXME!!!
/* the pad we're associated with */
GstPad *pad;
gboolean issink;
/* visual stuff */
GnomeCanvasGroup *group;
GnomeCanvasItem *border,*title,*padbox;
gboolean sinkpad; // is this a sink pad?
gdouble x,y; // location
gdouble width,height; // actual size
gdouble boxwidth,boxheight; // size of pad box
gboolean resize; // does it need resizing?
/* interaction state */
gboolean dragging,resizing,moved;
gdouble dragx,dragy;
/* connection */
// GnomeCanvasItem *connection; // can't use
//GstEditorConnection
};
struct _GstEditorPadClass {
GtkObjectClass parent_class;
};
GtkType gst_editor_pad_get_type();
GstEditorPad *gst_editor_pad_new(GstEditorElement *parent,GstPad *pad,
const gchar *first_arg_name, ...);
void gst_editor_pad_construct(GstEditorPad *element,
GstEditorElement *parent,
const gchar *first_arg_name,va_list args);
#endif /* __GST_EDITOR_PAD_H__ */

278
editor/gstelementselect.c Normal file
View file

@ -0,0 +1,278 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
#include <gnome.h>
struct element_select_classlist {
gchar *name;
GSList *subclasses;
GSList *factories;
};
struct element_select_details {
GstElementFactory *factory;
GtkWidget *longname, *description, *version, *author, *copyright;
};
static gint compare_name(gconstpointer a,gconstpointer b) {
return (strcmp(((GstElementFactory *)a)->name,
((GstElementFactory *)b)->name));
}
gint str_compare(gconstpointer a,gconstpointer b) {
return (strcmp((gchar *)a,(gchar *)b));
}
/* this function creates a GtkCTreeNode with the contents of the classtree */
static void make_ctree(GtkCTree *tree,GtkCTreeNode *parent,
struct element_select_classlist *class) {
GSList *traverse;
GtkCTreeNode *classnode, *node = NULL;
gchar *data[2];
data[0] = g_strdup(class->name);
data[1] = NULL;
classnode = gtk_ctree_insert_node(tree,parent,NULL,data,0,
NULL,NULL,NULL,NULL,FALSE,TRUE);
gtk_ctree_node_set_selectable(tree,classnode,FALSE);
traverse = class->subclasses;
while (traverse) {
make_ctree(tree,classnode,
(struct element_select_classlist *)(traverse->data));
traverse = g_slist_next(traverse);
}
traverse = class->factories;
while (traverse) {
GstElementFactory *factory = (GstElementFactory *)(traverse->data);
data[0] = g_strdup(factory->name);
data[1] = g_strdup(factory->details->description);
node = gtk_ctree_insert_node(tree,classnode,NULL,data,0,
NULL,NULL,NULL,NULL,TRUE,FALSE);
gtk_ctree_node_set_row_data_full(tree,node,factory,NULL);
traverse = g_slist_next(traverse);
}
}
static void ctree_select(GtkWidget *widget,gint row,gint column,
GdkEventButton *bevent,gpointer data) {
GtkCTree *tree = GTK_CTREE(widget);
GtkCTreeNode *node;
GstElementFactory *factory;
struct element_select_details *details;
node = gtk_ctree_node_nth(tree,row);
factory = (GstElementFactory *)gtk_ctree_node_get_row_data(tree,node);
if (!factory)
return;
details = (struct element_select_details *)data;
details->factory = factory;
gtk_entry_set_text(GTK_ENTRY(details->longname),
factory->details->longname);
gtk_entry_set_text(GTK_ENTRY(details->description),
factory->details->description);
gtk_entry_set_text(GTK_ENTRY(details->version),
factory->details->version);
gtk_entry_set_text(GTK_ENTRY(details->author),
factory->details->author);
gtk_entry_set_text(GTK_ENTRY(details->copyright),
factory->details->copyright);
if (bevent && bevent->type == GDK_2BUTTON_PRESS)
gtk_main_quit();
}
GstElementFactory *element_select_dialog() {
GtkWidget *dialog;
gchar *titles[2];
GtkWidget *ctree;
GtkWidget *scroller;
GtkTable *table;
GtkWidget *detailslabel;
GtkWidget *detailshsep;
GtkWidget *longname, *description, *version, *author, *copyright;
GList *elements;
GstElementFactory *element;
gchar **classes, **class;
GSList *classlist;
GSList *classtree, *treewalk;
GSList **curlist;
struct element_select_classlist *branch;
struct element_select_details details;
/* first create the dialog and associated stuff */
dialog = gnome_dialog_new("Select Element",
GNOME_STOCK_BUTTON_OK,
GNOME_STOCK_BUTTON_CANCEL,
NULL);
gnome_dialog_set_close(GNOME_DIALOG(dialog),TRUE);
gnome_dialog_close_hides(GNOME_DIALOG(dialog),TRUE);
gnome_dialog_set_default(GNOME_DIALOG(dialog),GNOME_OK);
titles[0] = "Element ";
titles[1] = "Description";
ctree = gtk_ctree_new_with_titles(2,0,titles);
gtk_widget_set_usize(ctree,400,350);
scroller = gtk_scrolled_window_new(NULL,NULL);
gtk_container_add(GTK_CONTAINER(scroller),ctree);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),scroller,
TRUE,TRUE,0);
/* create the details table and put a title on it */
table = GTK_TABLE(gtk_table_new(2,7,FALSE));
detailslabel = gtk_label_new("Element Details:");
gtk_misc_set_alignment(GTK_MISC(detailslabel),0.0,0.5);
gtk_table_attach(table,detailslabel,0,2,0,1,GTK_FILL|GTK_EXPAND,0,0,0);
/* then a separator to keep the title separate */
detailshsep = gtk_hseparator_new();
gtk_table_attach(table,detailshsep,0,2,1,2,GTK_FILL|GTK_EXPAND,0,0,0);
/* the long name of the element */
longname = gtk_label_new("Name:");
gtk_misc_set_alignment(GTK_MISC(longname),1.0,0.5);
gtk_table_attach(table,longname,0,1,2,3,GTK_FILL,0,5,0);
details.longname = gtk_entry_new();
gtk_entry_set_editable(GTK_ENTRY(details.longname),FALSE);
gtk_table_attach(table,details.longname,1,2,2,3,GTK_FILL|GTK_EXPAND,0,0,0);
/* the description */
description = gtk_label_new("Description:");
gtk_misc_set_alignment(GTK_MISC(description),1.0,0.5);
gtk_table_attach(table,description,0,1,3,4,GTK_FILL,0,5,0);
details.description = gtk_entry_new();
gtk_entry_set_editable(GTK_ENTRY(details.description),FALSE);
gtk_table_attach(table,details.description,1,2,3,4,GTK_FILL|GTK_EXPAND,0,0,0);
/* the version */
version = gtk_label_new("Version:");
gtk_misc_set_alignment(GTK_MISC(version),1.0,0.5);
gtk_table_attach(table,version,0,1,4,5,GTK_FILL,0,5,0);
details.version = gtk_entry_new();
gtk_entry_set_editable(GTK_ENTRY(details.version),FALSE);
gtk_table_attach(table,details.version,1,2,4,5,GTK_FILL|GTK_EXPAND,0,0,0);
/* the author */
author = gtk_label_new("Author:");
gtk_misc_set_alignment(GTK_MISC(author),1.0,0.5);
gtk_table_attach(table,author,0,1,6,7,GTK_FILL,0,5,0);
details.author = gtk_entry_new();
gtk_entry_set_editable(GTK_ENTRY(details.author),FALSE);
gtk_table_attach(table,details.author,1,2,6,7,GTK_FILL|GTK_EXPAND,0,0,0);
/* the copyright */
copyright = gtk_label_new("Copyright:");
gtk_misc_set_alignment(GTK_MISC(copyright),1.0,0.5);
gtk_table_attach(table,copyright,0,1,7,8,GTK_FILL,0,5,0);
details.copyright = gtk_entry_new();
gtk_entry_set_editable(GTK_ENTRY(details.copyright),FALSE);
gtk_table_attach(table,details.copyright,1,2,7,8,GTK_FILL|GTK_EXPAND,0,0,0);
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),GTK_WIDGET(table),
TRUE,TRUE,0);
/* first create a sorted (by class) tree of all the factories */
classtree = NULL;
elements = gst_elementfactory_get_list();
while (elements) {
element = (GstElementFactory *)(elements->data);
/* split up the factory's class */
classes = g_strsplit(element->details->class,"/",0);
class = classes;
curlist = &classtree;
/* walk down the class tree to find where to place this element */
/* the goal is for treewalk to point to the right class branch */
/* when we exit this thing, branch is pointing where we want */
while (*class) {
treewalk = *curlist;
/* walk the current level of class to see if we have the class */
while (treewalk) {
branch = (struct element_select_classlist *)(treewalk->data);
/* see if this class matches what we're looking for */
if (!strcmp(branch->name,*class)) {
/* if so, we progress down the list into this one's list */
curlist = &branch->subclasses;
break;
}
treewalk = g_slist_next(treewalk);
}
/* if treewalk == NULL, it wasn't in the list. add one */
if (treewalk == NULL) {
/* curlist is pointer to list */
branch = g_new0(struct element_select_classlist,1);
branch->name = g_strdup(*class);
*curlist = g_slist_insert_sorted(*curlist,branch,str_compare);
curlist = &branch->subclasses;
}
class++;
}
/* theoretically branch points where we want now */
branch->factories = g_slist_insert_sorted(branch->factories,element,
compare_name);
elements = g_list_next(elements);
}
/* now fill in the ... */
gtk_clist_freeze(GTK_CLIST(ctree));
treewalk = classtree;
while (treewalk) {
make_ctree(GTK_CTREE(ctree),NULL,
(struct element_select_classlist *)(treewalk->data));
treewalk = g_slist_next(treewalk);
}
gtk_clist_thaw(GTK_CLIST(ctree));
gtk_signal_connect(GTK_OBJECT(ctree),"select_row",
GTK_SIGNAL_FUNC(ctree_select),&details);
gtk_widget_show_all(GTK_WIDGET(dialog));
details.factory = NULL;
if (gnome_dialog_run_and_close(GNOME_DIALOG(dialog)) == GNOME_CANCEL)
return NULL;
else
return details.factory;
};
/* this is available so we can do a quick test of this thing */
#ifdef ELEMENTSELECT_MAIN
int main(int argc,char *argv[]) {
GstElementFactory *chosen;
gst_init(&argc,&argv);
gst_plugin_load_all();
gnome_init("elementselect_test","0.0.0",argc,argv);
chosen = element_select_dialog();
if (chosen)
g_print("selected '%s'\n",chosen->name);
else
g_print("didn't choose any\n");
exit(0);
}
#endif /* ELEMENTSELECT_MAIN */

23
editor/gstelementselect.h Normal file
View file

@ -0,0 +1,23 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
GstElementFactory *element_select_dialog();

5
gst/xml/Makefile.am Normal file
View file

@ -0,0 +1,5 @@
bin_PROGRAMS = save
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) $(XML_CFLAGS) -I$(top_srcdir)
LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(XML_LIBS) $(top_srcdir)/gst/libgst.la

6
gst/xml/notes Normal file
View file

@ -0,0 +1,6 @@
The naming hiearchy you'll see bits of but never the whole thing is
basically container:container:container:element.pad, which reflects
parentage. When naming connections between elements, those are the what
will be used, possibly along with .. as container to indicate 'up one'. I
don't think this will ever by used, since ghost pads are supposed to make
all connections between elements with the same parent.

43
gst/xml/save.c Normal file
View file

@ -0,0 +1,43 @@
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
GstPipeline *create_pipeline() {
GstPipeline *pipeline;
GstElement *src, *sink;
GstPad *srcpad, *sinkpad;
pipeline = gst_pipeline_new("fake_pipeline");
g_return_if_fail(pipeline != NULL);
src = gst_elementfactory_make("fakesrc","fakesrc");
g_return_if_fail(src != NULL);
sink = gst_elementfactory_make("fakesink","fakesink");
g_return_if_fail(sink != NULL);
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(sink));
srcpad = gst_element_get_pad(src,"src");
g_return_if_fail(srcpad != NULL);
sinkpad = gst_element_get_pad(sink,"sink");
g_return_if_fail(srcpad != NULL);
gst_pad_connect(srcpad,sinkpad);
return GST_PIPELINE(pipeline);
}
int main(int argc,char *argv[]) {
GstElement *pipeline;
xmlDocPtr doc;
// _gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
pipeline = GST_ELEMENT(create_pipeline());
doc = gst_xml_write(pipeline);
xmlSaveFile("save.xml",doc);
}

21
test/Makefile.am Normal file
View file

@ -0,0 +1,21 @@
#bin_PROGRAMS = basic m types a r plugin w s args mpg123 mcut push qtest
bin_PROGRAMS = qtest spectrum record wave mp3 teardown buffer mp3parse \
mpeg2parse mp3play ac3parse ac3play dvdcat fake cobin
SUBDIRS = xml cothreads
spectrum_CFLAGS = $(shell gnome-config --cflags gnomeui)
spectrum_LDFLAGS = $(shell gnome-config --libs gnomeui)
wave_CFLAGS = $(shell gnome-config --cflags gnomeui)
wave_LDFLAGS = $(shell gnome-config --libs gnomeui)
buffer_SOURCES = buffer.c mem.c
teardown_SOURCES = teardown.c mem.c
ac3play_SOURCES = ac3play.c mem.c
LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) -I$(top_srcdir) \
$(shell gnome-config --cflags gnomeui)
EXTRA_DIST = README

69
test/a.c Normal file
View file

@ -0,0 +1,69 @@
#include <gst/gst.h>
void eof(GstSrc *src) {
g_print("have eof, quitting\n");
exit(0);
}
int main(int argc,char *argv[]) {
GstType *autype;
GList *factories;
GstElementFactory *parsefactory;
GstElement *bin, *disksrc, *parse, *audiosink;
GList *padlist;
gst_init(&argc,&argv);
gst_plugin_load_all();
bin = gst_bin_new("bin");
disksrc = gst_disksrc_new("disksrc");
g_print("created disksrc\n");
if (argc == 2)
gst_disksrc_set_filename(disksrc,argv[1]);
else
gst_disksrc_set_filename(disksrc,"Thank_you_very_much.au");
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
/* now it's time to get the parser */
autype = gst_type_get_by_mime("audio/au");
factories = gst_type_get_sinks(autype);
if (factories != NULL)
parsefactory = GST_ELEMENTFACTORY(factories->data);
else {
g_print("sorry, can't find anyone registered to sink 'au'\n");
return 1;
}
parse = gst_elementfactory_create(parsefactory,"parser");
if (parse == NULL) {
g_print("sorry, couldn't create parser\n");
return 1;
}
audiosink = gst_audiosink_new("audiosink");
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
gst_element_get_pad(audiosink,"sink"));
while(1)
gst_disksrc_push(GST_SRC(disksrc));
gst_object_destroy(GST_OBJECT(audiosink));
gst_object_destroy(GST_OBJECT(parse));
gst_object_destroy(GST_OBJECT(disksrc));
gst_object_destroy(GST_OBJECT(bin));
}

55
test/ac3parse.c Normal file
View file

@ -0,0 +1,55 @@
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
void ac3parse_info_chain(GstPad *pad,GstBuffer *buf) {
g_print("got buffer of size %d\n",GST_BUFFER_SIZE(buf));
gst_buffer_unref(buf);
}
int main(int argc,char *argv[]) {
GstPipeline *pipeline;
GstElementFactory *srcfactory, *parsefactory;
GstElement *src, *parse;
GstPad *infopad;
g_print("have %d args\n",argc);
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
// gst_plugin_load("ac3parse");
gst_plugin_load_all();
pipeline = gst_pipeline_new("pipeline");
g_return_if_fail(pipeline != NULL);
srcfactory = gst_elementfactory_find("disksrc");
g_return_if_fail(srcfactory != NULL);
parsefactory = gst_elementfactory_find("ac3parse");
g_return_if_fail(parsefactory != NULL);
src = gst_elementfactory_create(srcfactory,"src");
g_return_if_fail(src != NULL);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],"bytesperread",4096,NULL);
g_print("should be using file '%s'\n",argv[1]);
parse = gst_elementfactory_create(parsefactory,"parse");
g_return_if_fail(parse != NULL);
infopad = gst_pad_new("sink",GST_PAD_SINK);
gst_pad_set_chain_function(infopad,ac3parse_info_chain);
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
infopad);
g_print("setting to RUNNING state\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
g_print("about to enter loop\n");
while (1)
gst_src_push(GST_SRC(src));
}

84
test/ac3play.c Normal file
View file

@ -0,0 +1,84 @@
#include <gst/gst.h>
#include "mem.h"
extern gboolean _gst_plugin_spew;
int main(int argc,char *argv[]) {
GstElement *pipeline, *decodethread, *playthread;
GstElement *src, *parse, *decode, *play;
GstElement *queue;
GstPad *infopad;
g_print("have %d args\n",argc);
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
// gst_plugin_load("ac3parse");
gst_plugin_load_all();
pipeline = gst_elementfactory_make("pipeline","ac3player");
g_return_if_fail(pipeline != NULL);
decodethread = gst_elementfactory_make("thread","decodethread");
g_return_if_fail(decodethread != NULL);
playthread = gst_elementfactory_make("thread","playthread");
g_return_if_fail(playthread != NULL);
queue = gst_elementfactory_make("queue","queue");
g_return_if_fail(queue != NULL);
src = gst_elementfactory_make("disksrc","src");
g_return_if_fail(src != NULL);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
g_print("should be using file '%s'\n",argv[1]);
parse = gst_elementfactory_make("ac3parse","parse");
g_return_if_fail(parse != NULL);
decode = gst_elementfactory_make("ac3dec","decode");
g_return_if_fail(decode != NULL);
play = gst_elementfactory_make("audiosink","play");
g_return_if_fail(play != NULL);
// construct the decode thread
g_print("constructing the decode thread\n");
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(src));
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(parse));
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(decode));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
gst_element_get_pad(decode,"sink"));
gst_element_add_ghost_pad(GST_ELEMENT(decodethread),
gst_element_get_pad(decode,"src"));
// construct the play thread
g_print("constructing the play thread\n");
gst_bin_add(GST_BIN(playthread),GST_ELEMENT(play));
gst_element_add_ghost_pad(GST_ELEMENT(playthread),
gst_element_get_pad(play,"sink"));
// construct the outer pipeline
g_print("constructing the main pipeline\n");
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(decodethread));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(queue));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(playthread));
gst_pad_connect(gst_element_get_pad(decodethread,"src"),
gst_element_get_pad(queue,"sink"));
gst_pad_connect(gst_element_get_pad(queue,"src"),
gst_element_get_pad(playthread,"sink"));
// set thread start state
gtk_object_set(GTK_OBJECT(decodethread),"create_thread",TRUE,NULL);
gtk_object_set(GTK_OBJECT(playthread),"create_thread",FALSE,NULL);
g_print("setting to RUNNING state\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
// sleep(1);
g_print("about to enter loop\n");
while (1) {
gst_thread_iterate(GST_THREAD(playthread));
g_print("using %d bytes\n",vmsize());
}
xmlSaveFile("ac3play.xml",gst_xml_write(GST_ELEMENT(pipeline)));
}

24
test/ac3sync.c Normal file
View file

@ -0,0 +1,24 @@
#include <stdio.h>
#include <fcntl.h>
int main(int argc,char *argv[]) {
int fd;
int offset = 0;
int got;
unsigned short buf[2048];
int i;
int prev = 0;
if (argc >= 2) fd = open(argv[1],O_RDONLY);
else fd = 0;
while (got = read(fd,buf,sizeof(buf))) {
for (i=0;i<(got/2);i++) {
if (buf[i] == 0x770b) {
printf("have sync at %d (+%d)\n",offset+(i*2),(offset+(i*2))-prev);
prev = offset+(i*2);
}
}
offset += got;
}
}

20
test/args.c Normal file
View file

@ -0,0 +1,20 @@
#include <glib.h>
#include <gst/gst.h>
int main(int argc,char *argv[]) {
GstElement *src;
GList *padlist;
GtkArg arg;
gst_init(&argc,&argv);
src = gst_disksrc_new("fakesrc");
gtk_object_set(GTK_OBJECT(src),"location","demo.mp3",NULL);
arg.name = "location";
gtk_object_getv(GTK_OBJECT(src),1,&arg);
g_print("location is %s\n",GTK_VALUE_STRING(arg));
gst_object_destroy(GST_OBJECT(src));
}

109
test/basic.c Normal file
View file

@ -0,0 +1,109 @@
#include <glib.h>
#include <gst/gst.h>
void added_child(GstObject *object,GstObject *child) {
g_print("added_child(): added child '%s' to '%s'\n",
gst_object_get_name(child),
gst_object_get_name(object));
}
void added_parent(GstObject *object,GstObject *parent) {
g_print("added_parent(): object '%s' has new parent '%s'\n",
gst_object_get_name(object),
gst_object_get_name(parent));
}
void list_pads(GstElement *element) {
GList *padlist;
padlist = gst_element_get_pad_list(element);
if (padlist == NULL)
g_print("%s has no pads...\n",gst_object_get_name(element));
else {
while (padlist) {
GstPad *pad = GST_PAD(padlist->data);
if (gst_pad_get_ghost_parent(pad) == GST_OBJECT(element))
g_print("'%s' had %s ghost pad '%s'\n",gst_object_get_name(element),
(gst_pad_get_direction(pad) == GST_PAD_SRC) ? "SRC" : "SINK",
gst_pad_get_name(pad));
else
g_print("'%s' had %s pad '%s'\n",gst_object_get_name(element),
(gst_pad_get_direction(pad) == GST_PAD_SRC) ? "SRC" : "SINK",
gst_pad_get_name(pad));
padlist = g_list_next(padlist);
}
}
}
int main(int argc,char *argv[]) {
GstElement *bin, *src, *binf, *filter1, *filter2, *sink;
GList *padlist;
gtk_init(&argc,&argv);
bin = gst_bin_new("bin");
src = gst_disksrc_new("fakesrc");
gst_disksrc_set_filename(src,"demo.mp3");
list_pads(src);
binf = gst_bin_new("binf");
filter1 = gst_fakefilter_new("filter1");
list_pads(filter1);
filter2 = gst_fakefilter_new("filter2");
list_pads(filter2);
sink = gst_fakesink_new("fakesink");
list_pads(sink);
gtk_signal_connect(GTK_OBJECT(bin),"object_added",
GTK_SIGNAL_FUNC(added_child),NULL);
gtk_signal_connect(GTK_OBJECT(binf),"object_added",
GTK_SIGNAL_FUNC(added_child),NULL);
gtk_signal_connect(GTK_OBJECT(binf),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
gtk_signal_connect(GTK_OBJECT(src),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
gtk_signal_connect(GTK_OBJECT(filter1),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
gtk_signal_connect(GTK_OBJECT(filter2),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
gtk_signal_connect(GTK_OBJECT(sink),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
/* add filter1 to the subbin */
gst_bin_add(GST_BIN(binf),GST_ELEMENT(filter1));
gst_bin_add(GST_BIN(binf),GST_ELEMENT(filter2));
/* connect the two together */
gst_pad_connect(gst_element_get_pad(filter1,"src"),
gst_element_get_pad(filter2,"sink"));
/* export the pads */
gst_element_add_ghost_pad(binf,gst_element_get_pad(filter1,"sink"));
gst_element_add_ghost_pad(binf,gst_element_get_pad(filter2,"src"));
list_pads(binf);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),GST_OBJECT(src));
gst_bin_add(GST_BIN(bin),GST_OBJECT(binf));
gst_bin_add(GST_BIN(bin),GST_OBJECT(sink));
/* connect src to binf */
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(binf,"sink"));
/* connect binf to sink */
gst_pad_connect(gst_element_get_pad(binf,"src"),
gst_element_get_pad(sink,"sink"));
gst_disksrc_push(GST_SRC(src));
gst_object_destroy(GST_OBJECT(src));
gst_object_destroy(GST_OBJECT(filter1));
gst_object_destroy(GST_OBJECT(filter2));
gst_object_destroy(GST_OBJECT(binf));
gst_object_destroy(GST_OBJECT(sink));
gst_object_destroy(GST_OBJECT(bin));
}

11
test/bindings/Makefile.am Normal file
View file

@ -0,0 +1,11 @@
lib_LTLIBRARIES = libcrashtest.la
libcrashtest_la_SOURCES = \
dummy.c
include_HEADERS = \
dummy.h
bin_PROGRAMS = test
test_LDADD = libcrashtest.la

20
test/bindings/dummy.c Normal file
View file

@ -0,0 +1,20 @@
#include <dummy.h>
Dummy *dummy_new() {
Dummy *dummy;
dummy = g_malloc(sizeof(Dummy));
dummy->flags = 0;
dummy->name = NULL;
return dummy;
}
Dummy *dummy_new_with_name(gchar *name) {
Dummy *dummy = dummy_new();
dummy->name = g_strdup(name);
return dummy;
}

19
test/bindings/dummy.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef __DUMMY_H__
#define __DUMMY_H__
#include <glib.h>
#define DUMMY(dummy) ((Dummy *)(dummy))
typedef struct _Dummy Dummy;
struct _Dummy {
gint flags;
gchar *name;
};
Dummy *dummy_new();
Dummy *dummy_new_with_name(gchar *name);
#endif /* __DUMMY_H__ */

11
test/bindings/test.c Normal file
View file

@ -0,0 +1,11 @@
#include <glib.h>
#include <dummy.h>
int main(int argc,char *argv[]) {
Dummy *driver,*passenger;
driver = dummy_new();
passenger = dummy_new_with_name("moron");
g_print("created a couple of dummies, %p and %p\n",driver,passenger);
}

53
test/buffer.c Normal file
View file

@ -0,0 +1,53 @@
#include <stdlib.h>
#include <glib.h>
#include <gst/gst.h>
#include "mem.h"
int main(int argc,char *argv[]) {
GstBuffer *buf;
GstBuffer **buffers;
gpointer dummy;
int i,max;
long usage1,usage2;
gst_init(&argc,&argv);
max = atoi(argv[1]);
g_print("creating and destroying a buffer %d times...",max);
usage1 = vmsize();
for (i=0;i<max;i++) {
buf = gst_buffer_new();
gst_buffer_unref(buf);
}
usage2 = vmsize();
g_print(" used %d more bytes\n",usage2-usage1);
// g_print("pre-allocating space...");
// usage1 = vmsize();
// dummy = g_malloc(100*i);
// usage2 = vmsize();
// g_print(" (+%d)\n",usage2-usage1);
g_print("creating %d buffers...",max);
buffers = g_new(GstBuffer,i);
usage1 = vmsize();
for (i=0;i<max;i++)
buffers[i] = gst_buffer_new();
// buffers[i] = (GstBuffer *)g_malloc(1024);
usage2 = vmsize();
g_print(" (+%d bytes), and destroying them...",usage2-usage1);
usage1 = vmsize();
for (i=0;i<max;i++)
gst_buffer_unref(buffers[i]);
// g_free(buffers[i]);
usage2 = vmsize();
g_print("(-%d)\n",usage1-usage2);
g_free(buffers);
g_print("buffer is %d bytes, list is %d bytes\n",
sizeof(GstBuffer),sizeof(GList));
g_print("memory usage is %d\n",vmsize());
}

42
test/cobin.c Normal file
View file

@ -0,0 +1,42 @@
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
int main(int argc,char *argv[]) {
GstElement *bin;
GstElement *src, *identity, *sink;
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
gst_plugin_load_all();
bin = gst_elementfactory_make("bin","bin");
g_return_if_fail(bin != NULL);
g_print("--- creating src and sink elements\n");
src = gst_elementfactory_make("fakesrc","src");
g_return_if_fail(src != NULL);
identity = gst_elementfactory_make(argv[1],"identity");
g_return_if_fail(identity != NULL);
sink = gst_elementfactory_make("fakesink","sink");
g_return_if_fail(sink != NULL);
g_print("--- about to add the elements to the pipeline\n");
gst_bin_add(GST_BIN(bin),GST_ELEMENT(src));
gst_bin_add(GST_BIN(bin),GST_ELEMENT(identity));
gst_bin_add(GST_BIN(bin),GST_ELEMENT(sink));
g_print("--- connecting\n");
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(identity,"sink"));
gst_pad_connect(gst_element_get_pad(identity,"src"),
gst_element_get_pad(sink,"sink"));
g_print("--- creating a plan\n");
gst_bin_create_plan(GST_BIN(bin));
g_print("--- starting up\n");
gst_bin_iterate(GST_BIN(bin));
g_print("\n");
}

View file

@ -0,0 +1,5 @@
bin_PROGRAMS = test simple
test_SOURCES = test.c cothreads.c object.c looper.c
simple_SOURCES = simple.c cothreads.c

143
test/cothreads/cothreads.c Normal file
View file

@ -0,0 +1,143 @@
#include <sys/time.h>
#include <linux/linkage.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/mman.h>
#include "cothreads.h"
pthread_key_t _cothread_key = -1;
cothread_state *cothread_create(cothread_context *ctx) {
cothread_state *s;
if (pthread_self() == 0) {
s = (cothread_state *)malloc(sizeof(int) * COTHREAD_STACKSIZE);
} else {
char *sp = CURRENT_STACK_FRAME;
unsigned long *stack_end = (unsigned long *)((unsigned long)sp &
~(STACK_SIZE - 1));
s = (cothread_state *)(stack_end + ((ctx->nthreads - 1) *
COTHREAD_STACKSIZE));
if (mmap((char *)s,COTHREAD_STACKSIZE*(sizeof(int)),
PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE|MAP_ANONYMOUS,
-1,0) < 0) {
perror("mmap'ing cothread stack space");
return NULL;
}
}
s->ctx = ctx;
s->threadnum = ctx->nthreads;
s->flags = 0;
s->sp = (int *)(s + COTHREAD_STACKSIZE);
ctx->threads[ctx->nthreads++] = s;
// printf("created cothread at %p\n",s);
return s;
}
void cothread_setfunc(cothread_state *thread,cothread_func func,int argc,char **argv) {
thread->func = func;
thread->argc = argc;
thread->argv = argv;
thread->pc = (int *)func;
}
cothread_context *cothread_init() {
cothread_context *ctx = (cothread_context *)malloc(sizeof(cothread_context));
if (_cothread_key == -1) {
if (pthread_key_create(&_cothread_key,NULL) != 0) {
perror("pthread_key_create");
return;
}
}
pthread_setspecific(_cothread_key,ctx);
memset(ctx->threads,0,sizeof(ctx->threads));
ctx->threads[0] = (cothread_state *)malloc(sizeof(cothread_state));
ctx->threads[0]->ctx = ctx;
ctx->threads[0]->threadnum = 0;
ctx->threads[0]->func = NULL;
ctx->threads[0]->argc = 0;
ctx->threads[0]->argv = NULL;
ctx->threads[0]->flags = COTHREAD_STARTED;
ctx->threads[0]->sp = CURRENT_STACK_FRAME;
ctx->threads[0]->pc = 0;
// fprintf(stderr,"0th thread is at %p\n",ctx->threads[0]);
// we consider the initiating process to be cothread 0
ctx->nthreads = 1;
ctx->current = 0;
return ctx;
}
cothread_state *cothread_main(cothread_context *ctx) {
// fprintf(stderr,"returning %p, the 0th cothread\n",ctx->threads[0]);
return ctx->threads[0];
}
void cothread_stub() {
cothread_context *ctx = pthread_getspecific(_cothread_key);
register cothread_state *thread = ctx->threads[ctx->current];
thread->flags |= COTHREAD_STARTED;
thread->func(thread->argc,thread->argv);
thread->flags &= ~COTHREAD_STARTED;
thread->pc = 0;
// printf("uh, yeah, we shouldn't be here, but we should deal anyway\n");
}
void cothread_switch(cothread_state *thread) {
cothread_context *ctx;
cothread_state *current;
int enter = 0;
// int i;
if (thread == NULL)
return;
ctx = thread->ctx;
current = ctx->threads[ctx->current];
if (current == NULL) {
fprintf(stderr,"there's no current thread, help!\n");
exit(2);
}
if (current == thread) {
fprintf(stderr,"trying to switch to same thread, legal but not necessary\n");
return;
}
// find the number of the thread to switch to
ctx->current = thread->threadnum;
// fprintf(stderr,"about to switch to thread #%d\n",ctx->current);
/* save the current stack pointer, frame pointer, and pc */
__asm__("movl %%esp, %0" : "=m"(current->sp) : : "esp", "ebp");
enter = setjmp(current->jmp);
if (enter != 0)
return;
enter = 1;
/* restore stack pointer and other stuff of new cothread */
__asm__("movl %0, %%esp\n" : "=m"(thread->sp));
if (thread->flags & COTHREAD_STARTED) {
// switch to it
longjmp(thread->jmp,1);
} else {
// start it
__asm__("jmp " SYMBOL_NAME_STR(cothread_stub));
}
}

View file

@ -0,0 +1,48 @@
#ifndef __COTHREADS_H__
#define __COTHREADS_H__
#include <setjmp.h>
#include <pthread.h>
#define COTHREAD_STACKSIZE 8192
#define COTHREAD_MAXTHREADS 16
#define STACK_SIZE 0x200000
#ifndef CURRENT_STACK_FRAME
#define CURRENT_STACK_FRAME ({ char __csf; &__csf; })
#endif /* CURRENT_STACK_FRAME */
typedef struct _cothread_state cothread_state;
typedef struct _cothread_context cothread_context;
typedef int (*cothread_func)(int argc,char **argv);
#define COTHREAD_STARTED 0x01
struct _cothread_state {
cothread_context *ctx;
int threadnum;
cothread_func func;
int argc;
char **argv;
int flags;
int *sp;
int *pc;
jmp_buf jmp;
};
struct _cothread_context {
cothread_state *threads[COTHREAD_MAXTHREADS];
int nthreads;
int current;
};
cothread_context *cothread_init();
cothread_state *cothread_create(cothread_context *ctx);
void cothread_setfunc(cothread_state *thread,cothread_func func,int argc,char **argv);
void cothread_switch(cothread_state *thread);
cothread_state *cothread_main(cothread_context *ctx);
#endif /* __COTHREAD_H__ */

47
test/cothreads/looper.c Normal file
View file

@ -0,0 +1,47 @@
#include <stdio.h>
#include "looper.h"
void looper_loopfunc(object *obj);
void looper_init(looper *l,int source) {
l->source = source;
object_setloopfunc(OBJECT(l),looper_loopfunc);
}
looper *looper_create(char *name,int source,cothread_context *ctx) {
looper *l = malloc(sizeof(looper));
if (l == NULL) {
fprintf(stderr,"sorry, couldn't allocate memory for looper\n");
exit(2);
}
object_init(OBJECT(l),name,ctx);
looper_init(l,source);
return l;
}
void looper_loopfunc(object *obj) {
looper *l = LOOPER(obj);
if (l->source) {
while (1) {
char *buf = malloc(11);
sprintf(buf,"Hello World!");
fprintf(stderr,"\npushing buffer %p with '%s'\n",buf,buf);
object_push(OBJECT(l)->peer,buf); // this should switch
}
} else {
while (1) {
char *buf;
fprintf(stderr,"\npulling buffer\n");
buf = object_pull(OBJECT(l));
printf("got %p: '%s' from peer\n",buf,buf);
free(buf);
// return to the main process now
cothread_switch(cothread_main(OBJECT(l)->threadstate->ctx));
sleep(1000);
}
}
}

18
test/cothreads/looper.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef __LOOPER_H__
#define __LOOPER_H__
#include "object.h"
#define LOOPER(l) ((looper *)(l))
typedef struct _looper looper;
struct _looper {
object object;
int source;
};
void looper_init(looper *l,int source);
looper *looper_create(char *name,int source,cothread_context *ctx);
#endif /* __LOOPER_H__ */

78
test/cothreads/object.c Normal file
View file

@ -0,0 +1,78 @@
#include <stdio.h>
#include "object.h"
int object_loop_function(int argc,char **argv) {
object *obj = OBJECT(argv);
printf("hey, in loopfunc for object %p\n",obj);
obj->loopfunc(obj);
}
void object_init(object *obj,char *name,cothread_context *ctx) {
obj->threadstate = cothread_create(ctx);
cothread_setfunc(obj->threadstate,object_loop_function,0,(char **)obj);
if (obj->threadstate == NULL) {
fprintf(stderr,"sorry, couldn't init threadstate\n");
exit(2);
}
obj->loopfunc = NULL;
obj->name = malloc(strlen(name));
memcpy(obj->name,name,strlen(name));
obj->peer = NULL;
}
object *object_create(char *name,cothread_context *ctx) {
object *obj = malloc(sizeof(object));
if (obj == NULL) {
printf("ack!\n");
exit(2);
}
memset(obj,0,sizeof(object));
object_init(obj,name,ctx);
return obj;
}
void object_setloopfunc(object *obj,object_loopfunc func) {
obj->loopfunc = func;
fprintf(stderr,"setting object loopfunc to %p\n",func);
}
void object_setpeer(object *obj,object *peer) {
obj->peer = peer;
peer->peer = obj;
printf("peered %p and %p\n",obj,peer);
}
void object_push(object *obj,char *buf) {
obj->pen = buf;
cothread_switch(obj->threadstate);
}
char *object_pull(object *obj) {
char *buf,i=0;
if (obj == NULL) fprintf(stderr,"obj is null\n");
if (obj->peer == NULL) fprintf(stderr,"obj->peer is null\n");
if (obj->peer->threadstate == NULL) fprintf(stderr,"obj->peer->threadstate is null\n");
while (obj->pen == NULL)
cothread_switch(obj->peer->threadstate),i++;
buf = obj->pen;
obj->pen = NULL;
fprintf(stderr,"took %d switches to get %p from pen\n",i,buf);
return buf;
}
void object_start(object *obj) {
if (!obj->threadstate || !obj->loopfunc) {
fprintf(stderr,"ack, not complete\n");
fprintf(stderr,"obj->threadstate is %p, obj->loopfunc is %p\n",
obj->threadstate,obj->loopfunc);
exit(2);
}
cothread_switch(obj->threadstate);
fprintf(stderr,"returned from cothread stuff into end of object_start()\n");
}

30
test/cothreads/object.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef __OBJECT_H__
#define __OBJECT_H__
#include "cothreads.h"
#define OBJECT(obj) ((object*)(obj))
typedef struct _object object;
typedef void (*object_loopfunc)(object *obj);
struct _object {
cothread_state *threadstate;
object_loopfunc loopfunc;
char *name;
object *peer;
void *pen;
};
void object_init(object *obj,char *name,cothread_context *ctx);
object *object_create(char *name,cothread_context *ctx);
void object_setloopfunc(object *obj,object_loopfunc func);
void object_setpeer(object *obj,object *peer);
void object_push(object *obj,char *buf);
char *object_pull(object *obj);
int object_loop_function(int argc,char **argv);
#endif /* __OBJECT_H__ */

23
test/cothreads/simple.c Normal file
View file

@ -0,0 +1,23 @@
#include <stdio.h>
#include "cothreads.h"
// cothread_context is passed in argv
int loopfunc(int argc,char **argv) {
fprintf(stderr,"SIMPLE: in loopfunc\n");
cothread_switch((cothread_context *)cothread_main(argv));
}
int main(int argc,char *argv[]) {
cothread_context *ctx;
cothread_state *state;
ctx = cothread_init();
state = cothread_create(ctx);
cothread_setfunc(state,loopfunc,0,(char **)ctx);
fprintf(stderr,"SIMPLE: about to switch to cothread 1\n");
cothread_switch(state);
fprintf(stderr,"SIMPLE: back from cothread_switch\n");
return 0;
}

17
test/cothreads/test.c Normal file
View file

@ -0,0 +1,17 @@
#include <stdio.h>
#include "cothreads.h"
#include "object.h"
#include "looper.h"
int main(int argc,char *argv[]) {
cothread_context *ctx = cothread_init();
looper *l1,*l2;
l1 = looper_create("looperone",1,ctx);
l2 = looper_create("loopertwo",0,ctx);
object_setpeer(OBJECT(l1),OBJECT(l2));
fprintf(stderr,"about to start l1\n\n");
object_start(l1);
}

46
test/dvdcat.c Normal file
View file

@ -0,0 +1,46 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
int main(int argc,char *argv[]) {
GstElement *pipeline;
GstElement *src, *sink;
int fd;
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
gst_plugin_load_all();
// gst_plugin_load("dvdsrc");
fd = creat("output.vob",0644);
pipeline = gst_elementfactory_make("pipeline","dvdcat");
g_return_if_fail(pipeline != NULL);
src = gst_elementfactory_make("dvdsrc","src");
g_return_if_fail(src != NULL);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
if (argc >= 3)
gtk_object_set(GTK_OBJECT(src),"offset",atoi(argv[2]),NULL);
sink = gst_elementfactory_make("fdsink","sink");
g_return_if_fail(sink != NULL);
gtk_object_set(GTK_OBJECT(sink),"fd",fd,NULL);
// construct the outer pipeline
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(sink));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(sink,"sink"));
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
// while (GST_STATE_IS_SET(src,GST_STATE_RUNNING))
// while (1)
while (GST_STATE_IS_SET(src,1<<16))
gst_src_push(GST_SRC(src));
}

37
test/fake.c Normal file
View file

@ -0,0 +1,37 @@
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
int main(int argc,char *argv[]) {
GstPipeline *pipeline;
GstElement *src, *sink;
GstPad *srcpad, *sinkpad;
// _gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
pipeline = gst_pipeline_new("pipeline");
g_return_if_fail(pipeline != NULL);
g_print("--- creating src and sink elements\n");
src = gst_elementfactory_make("fakesrc","src");
g_return_if_fail(src != NULL);
sink = gst_elementfactory_make("fakesink","sink");
g_return_if_fail(sink != NULL);
g_print("--- about to add the elements to the pipeline\n");
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(sink));
g_print("--- getting pads\n");
srcpad = gst_element_get_pad(src,"src");
g_return_if_fail(srcpad != NULL);
sinkpad = gst_element_get_pad(sink,"sink");
g_return_if_fail(srcpad != NULL);
g_print("--- connecting\n");
gst_pad_connect(srcpad,sinkpad);
g_print("--- setting up\n");
gst_pipeline_iterate(pipeline);
}

15
test/gsttracedump.c Normal file
View file

@ -0,0 +1,15 @@
#include <glib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <gst/gsttrace.h>
int main(int argc,char *argv[]) {
gchar *filename = argv[1];
int fd = open(filename,O_RDONLY);
GstTraceEntry entry;
while (read(fd,&entry,sizeof(entry)))
g_print("%Ld(%ld) 0x%08lx: %s\n",entry.timestamp,entry.sequence,
entry.data,entry.message);
}

26
test/jitter.c Normal file
View file

@ -0,0 +1,26 @@
#include <stdio.h>
int main() {
char line[256];
unsigned long long a = 0,b;
unsigned long long difference;
unsigned long long mindiff = -1, maxdiff = 0;
unsigned long long total = 0;
int samples = 0;
while (gets(line)) {
sscanf(line,"%Ld",&b);
if (a) {
difference = b - a;
printf("difference is %Ld\n",difference);
if (difference > maxdiff) maxdiff = difference;
if (difference < mindiff) mindiff = difference;
total += difference;
samples++;
}
a = b;
}
printf("min difference is %Ld, avg %Ld, max is %Ld\n",
mindiff,total/samples,maxdiff);
printf("jitter is %Ld\n",maxdiff-mindiff);
}

76
test/m.c Normal file
View file

@ -0,0 +1,76 @@
#include <gst/gst.h>
#include <unistd.h>
void eof(GstSrc *src) {
g_print("eof\n");
exit(0);
}
int main(int argc,char *argv[]) {
guint16 type;
GList *factories;
GstElementFactory *parsefactory;
GstElement *bin, *src, *parse, *sink;
GList *padlist;
guchar *filename;
if (argc == 2)
filename = argv[1];
else
filename = "-";
gst_init(&argc,&argv);
gst_plugin_load_all();
bin = gst_bin_new("bin");
if (!strcmp(filename,"-"))
src = gst_fdsrc_new_with_fd("src",STDIN_FILENO);
else if (!strncmp(filename,"http://",7))
src = gst_httpsrc_new_with_url("src",filename);
else
src = gst_asyncdisksrc_new_with_file("src",filename);
/* now it's time to get the parser */
type = gst_type_find_by_mime("audio/mpeg");
factories = gst_type_get_sinks(type);
if (factories != NULL)
parsefactory = GST_ELEMENTFACTORY(factories->data);
else {
g_print("sorry, can't find anyone registered to sink 'mp3'\n");
return 1;
}
parse = gst_elementfactory_create(parsefactory,"parser");
if (parse == NULL) {
g_print("sorry, couldn't create parser\n");
return 1;
}
sink = gst_audiosink_new("audiosink");
gtk_signal_connect(GTK_OBJECT(src),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),src);
gst_bin_add(GST_BIN(bin),parse);
gst_bin_add(GST_BIN(bin),sink);
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
gst_element_get_pad(sink,"sink"));
while(1) {
g_print(".");
gst_src_push(GST_SRC(src));
}
gst_object_destroy(GST_OBJECT(sink));
gst_object_destroy(GST_OBJECT(parse));
gst_object_destroy(GST_OBJECT(src));
gst_object_destroy(GST_OBJECT(bin));
}

77
test/mcut.c Normal file
View file

@ -0,0 +1,77 @@
#include <gst/gst.h>
void eof(GstSrc *src) {
g_print("have eof, quitting\n");
exit(0);
}
int main(int argc,char *argv[]) {
GstType *type;
GList *factories;
GstElementFactory *parsefactory;
GstElement *bin, *src, *parse, *sink;
GList *padlist;
guchar *filename;
glong length = 0, size = 4180, skip = 8360, offset = 0;
if (argc == 2)
filename = argv[1];
else {
g_print("sorry, need a filename now\n");
exit(1);
}
gst_init(&argc,&argv);
gst_plugin_load_all();
bin = gst_bin_new("bin");
src = gst_asyncdisksrc_new("src");
g_print("created disksrc\n");
gtk_object_set(GTK_OBJECT(src),"location",filename,NULL);
length = gst_util_get_long_arg(GST_OBJECT(src),"length");
g_print("file is %d bytes long\n",length);
/* now it's time to get the parser */
type = gst_type_get_by_mime("audio/mp3");
factories = gst_type_get_sinks(type);
if (factories != NULL)
parsefactory = GST_ELEMENTFACTORY(factories->data);
else {
g_print("sorry, can't find anyone registered to sink 'mp3'\n");
return 1;
}
parse = gst_elementfactory_create(parsefactory,"parser");
if (parse == NULL) {
g_print("sorry, couldn't create parser\n");
return 1;
}
sink = gst_audiosink_new("audiosink");
gtk_signal_connect(GTK_OBJECT(src),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),src);
gst_bin_add(GST_BIN(bin),parse);
gst_bin_add(GST_BIN(bin),sink);
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
gst_element_get_pad(sink,"sink"));
while(offset < length) {
gst_src_push_region(GST_SRC(src),offset,size);
offset += skip;
}
gst_object_destroy(GST_OBJECT(sink));
gst_object_destroy(GST_OBJECT(parse));
gst_object_destroy(GST_OBJECT(src));
gst_object_destroy(GST_OBJECT(bin));
}

22
test/mem.c Normal file
View file

@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int vmsize() {
int pid,fd,size,i,mem;
char filename[17], buf[256], *ptr, *end;
pid = getpid();
snprintf(filename,17,"/proc/%d/stat",pid);
fd = open(filename,O_RDONLY);
size = read(fd,buf,240);
ptr = buf;
for (i=0;i<22;i++)
ptr = (char *)strchr(ptr,' ') + 1;
end = (char *)strchr(ptr,' ');
*end = 0;
sscanf(ptr,"%d",&mem);
close(fd);
return mem;
}

1
test/mem.h Normal file
View file

@ -0,0 +1 @@
int vmsize();

63
test/mp3.c Normal file
View file

@ -0,0 +1,63 @@
#include <gnome.h>
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
static gboolean playing = TRUE;
void eof(GstSrc *src) {
DEBUG("have EOF\n");
playing = FALSE;
}
int main(int argc,char *argv[]) {
GstElement *bin;
GstElementFactory *srcfactory;
GstElement *src;
GstElementFactory *mp3factory;
GstElement *mp3;
GstElementFactory *sinkfactory;
GstElement *sink;
GtkWidget *appwindow;
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
gst_plugin_load_all();
bin = gst_bin_new("bin");
srcfactory = gst_elementfactory_find("disksrc");
if (argc == 3)
mp3factory = gst_elementfactory_find(argv[2]);
else
mp3factory = gst_elementfactory_find("xa");
sinkfactory = gst_elementfactory_find("audiosink");
src = gst_elementfactory_create(srcfactory,"src");
g_return_if_fail(src != NULL);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
mp3 = gst_elementfactory_create(mp3factory,"mp3");
g_return_if_fail(mp3 != NULL);
sink = gst_elementfactory_create(sinkfactory,"sink");
g_return_if_fail(sink != NULL);
gst_bin_add(GST_BIN(bin),GST_ELEMENT(src));
gst_bin_add(GST_BIN(bin),GST_ELEMENT(mp3));
gst_bin_add(GST_BIN(bin),GST_ELEMENT(sink));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(mp3,"sink"));
gst_pad_connect(gst_element_get_pad(mp3,"src"),
gst_element_get_pad(sink,"sink"));
gtk_signal_connect(GTK_OBJECT(src),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_RUNNING);
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_PLAYING);
while (playing)
gst_src_push(GST_SRC(src));
}

55
test/mp3parse.c Normal file
View file

@ -0,0 +1,55 @@
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
void mp3parse_info_chain(GstPad *pad,GstBuffer *buf) {
g_print("got buffer of size %d\n",GST_BUFFER_SIZE(buf));
gst_buffer_unref(buf);
}
int main(int argc,char *argv[]) {
GstPipeline *pipeline;
GstElementFactory *srcfactory, *parsefactory;
GstElement *src, *parse;
GstPad *infopad;
g_print("have %d args\n",argc);
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
// gst_plugin_load("mp3parse");
gst_plugin_load_all();
pipeline = gst_pipeline_new("pipeline");
g_return_if_fail(pipeline != NULL);
srcfactory = gst_elementfactory_find("disksrc");
g_return_if_fail(srcfactory != NULL);
parsefactory = gst_elementfactory_find("mp3parse");
g_return_if_fail(parsefactory != NULL);
src = gst_elementfactory_create(srcfactory,"src");
g_return_if_fail(src != NULL);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
g_print("should be using file '%s'\n",argv[1]);
parse = gst_elementfactory_create(parsefactory,"parse");
g_return_if_fail(parse != NULL);
infopad = gst_pad_new("sink",GST_PAD_SINK);
gst_pad_set_chain_function(infopad,mp3parse_info_chain);
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
infopad);
g_print("setting to RUNNING state\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
g_print("about to enter loop\n");
while (1)
gst_src_push(GST_SRC(src));
}

59
test/mp3play.c Normal file
View file

@ -0,0 +1,59 @@
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
int main(int argc,char *argv[]) {
GstPipeline *pipeline;
GstElementFactory *srcfactory, *parsefactory, *decodefactory, *playfactory;
GstElement *src, *parse, *decode, *play;
GstPad *infopad;
g_print("have %d args\n",argc);
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
// gst_plugin_load("mp3parse");
gst_plugin_load_all();
pipeline = gst_pipeline_new("pipeline");
g_return_if_fail(pipeline != NULL);
srcfactory = gst_elementfactory_find("disksrc");
g_return_if_fail(srcfactory != NULL);
parsefactory = gst_elementfactory_find("mp3parse");
g_return_if_fail(parsefactory != NULL);
decodefactory = gst_elementfactory_find("mpg123");
g_return_if_fail(decodefactory != NULL);
playfactory = gst_elementfactory_find("audiosink");
g_return_if_fail(playfactory != NULL);
src = gst_elementfactory_create(srcfactory,"src");
g_return_if_fail(src != NULL);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
g_print("should be using file '%s'\n",argv[1]);
parse = gst_elementfactory_create(parsefactory,"parse");
g_return_if_fail(parse != NULL);
decode = gst_elementfactory_create(decodefactory,"decode");
g_return_if_fail(decode != NULL);
play = gst_elementfactory_create(playfactory,"play");
g_return_if_fail(play != NULL);
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(decode));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(play));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
gst_element_get_pad(decode,"sink"));
gst_pad_connect(gst_element_get_pad(decode,"src"),
gst_element_get_pad(play,"sink"));
g_print("setting to RUNNING state\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
g_print("about to enter loop\n");
while (1)
gst_src_push(GST_SRC(src));
}

95
test/mpeg2parse.c Normal file
View file

@ -0,0 +1,95 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
static int ac3fd;
static gchar *desired_stream;
void mpeg2parse_write_ac3(GstPad *pad,GstBuffer *buf) {
g_print(".");
// g_print("MPEG2PARSE: got AC3 buffer of size %d\n",GST_BUFFER_SIZE(buf));
write(ac3fd,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
gst_buffer_unref(buf);
}
void mpeg2parse_info_chain(GstPad *pad,GstBuffer *buf) {
// g_print("MPEG2PARSE: got buffer of size %d\n",GST_BUFFER_SIZE(buf));
gst_buffer_unref(buf);
}
void mpeg2parse_newpad(GstElement *parser,GstPad *pad) {
GstPad *infopad;
g_print("MPEG2PARSE: have new pad \"%s\" from parser\n",
gst_pad_get_name(pad));
infopad = gst_pad_new("sink",GST_PAD_SINK);
if (strcmp(gst_pad_get_name(pad),desired_stream) == 0)
gst_pad_set_chain_function(infopad,mpeg2parse_write_ac3);
else
gst_pad_set_chain_function(infopad,mpeg2parse_info_chain);
gst_pad_connect(pad,infopad);
}
int main(int argc,char *argv[]) {
GstPipeline *pipeline;
GstElement *src, *parse, *out;
GstPad *infopad;
int i,c;
g_print("have %d args\n",argc);
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
// gst_plugin_load("mpeg2parse");
gst_plugin_load_all();
ac3fd = creat("output.ac3",S_IREAD|S_IWRITE);
pipeline = gst_pipeline_new("pipeline");
g_return_if_fail(pipeline != NULL);
if (strstr(argv[1],"video_ts")) {
src = gst_elementfactory_make("dvdsrc","src");
g_print("using DVD source\n");
} else
src = gst_elementfactory_make("disksrc","src");
g_return_if_fail(src != NULL);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
if (argc >= 3) {
gtk_object_set(GTK_OBJECT(src),"bytesperread",atoi(argv[2]),NULL);
g_print("block size is %d\n",atoi(argv[2]));
}
g_print("should be using file '%s'\n",argv[1]);
parse = gst_elementfactory_make("mpeg2parse","parse");
g_return_if_fail(parse != NULL);
gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad,NULL);
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
g_print("setting to RUNNING state\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
if (argc >= 4) c = atoi(argv[3]);
else c = 4;
g_print("c is %d\n",c);
if (argc >= 5) desired_stream = argv[4];
else desired_stream = "private_stream_1.0";
g_print("\n");
for (i=0;i<c;i++) {
g_print("\n");
gst_src_push(GST_SRC(src));
}
}

67
test/mpg123.c Normal file
View file

@ -0,0 +1,67 @@
#include <gst/gst.h>
void eof(GstSrc *src) {
g_print("have eof, quitting\n");
exit(0);
}
int main(int argc,char *argv[]) {
GList *factories;
GstElementFactory *parsefactory;
GstElement *bin, *disksrc, *parse, *audiosink;
GList *padlist;
guchar *filename;
int i;
if (argc == 2)
filename = argv[1];
else
filename = "ctp2.mp3";
gst_init(&argc,&argv);
gst_plugin_load_all();
g_print("\n");
bin = gst_bin_new("bin");
disksrc = gst_disksrc_new("disksrc");
g_print("created disksrc\n");
gtk_object_set(GTK_OBJECT(disksrc),"location",filename,NULL);
gtk_object_set(GTK_OBJECT(disksrc),"bytesperread",1048576,NULL);
/* now it's time to get the parser */
parsefactory = gst_plugin_find_elementfactory("xing");
parse = gst_elementfactory_create(parsefactory,"parser");
if (parse == NULL) {
g_print("sorry, couldn't create parser\n");
return 1;
}
audiosink = gst_audiosink_new("audiosink");
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
gst_element_get_pad(audiosink,"sink"));
for (i=0;i<4;i++) {
g_print("\n");
gst_disksrc_push(GST_SRC(disksrc));
}
gst_object_destroy(GST_OBJECT(audiosink));
gst_object_destroy(GST_OBJECT(parse));
gst_object_destroy(GST_OBJECT(disksrc));
gst_object_destroy(GST_OBJECT(bin));
}

55
test/p.c Normal file
View file

@ -0,0 +1,55 @@
#include <glib.h>
#include <gst/gst.h>
void eof(GstSrc *src) {
g_print("have eof, quitting\n");
exit(0);
}
int main(int argc,char *argv[]) {
GstElement *bin, *disksrc, *p, *audiosink;
GList *padlist;
gst_init(&argc,&argv);
bin = gst_bin_new("bin");
disksrc = gst_disksrc_new("disksrc");
g_print("created disksrc\n");
if (argc == 2)
gst_disksrc_set_filename(disksrc,argv[1]);
else
gst_disksrc_set_filename(disksrc,"mendelssohn.1.raw");
gst_disksrc_set_bytesperread(disksrc,32768);
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
p = gst_plugin_find_elementfactory("pipe");
audiosink = gst_audiosink_new("audiosink");
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
gst_bin_add(GST_BIN(bin),GST_OBJECT(p));
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
gst_element_get_pad(p,"sink"));
gst_pad_connect(gst_element_get_pad(p,"src"),
gst_element_get_pad(audiosink,"sink"));
/* set soundcard properties */
gst_audiosink_set_format(GST_AUDIOSINK(audiosink),AFMT_S16_BE);
gst_audiosink_set_channels(GST_AUDIOSINK(audiosink),2);
gst_audiosink_set_frequency(GST_AUDIOSINK(audiosink),44100);
while(1)
gst_disksrc_push(GST_SRC(disksrc));
gst_object_destroy(GST_OBJECT(audiosink));
gst_object_destroy(GST_OBJECT(disksrc));
gst_object_destroy(GST_OBJECT(bin));
}

17
test/plugin.c Normal file
View file

@ -0,0 +1,17 @@
#include <gst/gst.h>
int main(int argc,char *argv[]) {
GstElementFactory *parseau_factory;
GstElement *parseau;
gst_init(&argc,&argv);
gst_plugin_load_all();
parseau_factory = gst_plugin_find_elementfactory("parseau");
g_print("parseau_factory is %p\n",parseau_factory);
parseau = gst_elementfactory_create(parseau_factory,"parser");
g_print("got parseau '%s' from plugin!!!\n",
gst_object_get_name(GST_OBJECT(parseau)));
}

78
test/push.c Normal file
View file

@ -0,0 +1,78 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <gst/gst.h>
int eofflag = 0;
void eof(GstSrc *src) {
eofflag = 1;
}
int main(int argc,char *argv[]) {
struct sockaddr_in src_addr, dst_addr;
int sockaddrlen;
int lsock;
int one = 1;
int sndbuf = 4096;
int sock;
GstElement *src,*sink;
gst_init(&argc,&argv);
lsock = socket(AF_INET,SOCK_STREAM,0);
if (lsock < 0) {
perror("creating socket");
exit(1);
}
if (setsockopt(lsock,SOL_SOCKET,SO_REUSEADDR,&one,sizeof(one))) {
perror("setsockopt(SO_REUSEADDR)");
exit(1);
}
src_addr.sin_family = AF_INET;
src_addr.sin_addr.s_addr = INADDR_ANY;
src_addr.sin_port = htons(8001);
if (bind(lsock,(struct sockaddr *)&src_addr,sizeof(src_addr))) {
perror("binding");
exit(1);
}
if (setsockopt(lsock,SOL_SOCKET,SO_SNDBUF,(char *)&sndbuf,sizeof(sndbuf))) {
perror("setsockopt(SO_SNDBUF)");
exit(1);
}
g_print("listening\n");
listen(lsock,8);
sock = accept(lsock,(struct sockaddr *)&dst_addr,&sockaddrlen);
g_print("connected\n");
close(lsock);
g_print("creating pipeline\n");
src = gst_disksrc_new_with_location("src",argv[1]);
g_print("have src\n");
gtk_signal_connect(GTK_OBJECT(src),"eof",GTK_SIGNAL_FUNC(eof),NULL);
g_print("have eof signal\n");
sink = gst_fdsink_new_with_fd("sink",sock);
g_print("have sink\n");
g_print("connecting\n");
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(sink,"sink"));
g_print("pushing...\n");
while (!eofflag)
gst_src_push(GST_SRC(src));
sleep(1);
close(sock);
}

104
test/qtest.c Normal file
View file

@ -0,0 +1,104 @@
#include <glib.h>
#include <gst/gst.h>
#include <gst/elements/gstqueue.h>
extern gboolean _gst_plugin_spew;
/* we don't need a lock around the application's state yet, since it's 1
bit. as it gets more fleshed in, we'll need a lock so the callbacks
don't screw around with state unexpectedly */
static gboolean playing = TRUE;
void eof(GstSrc *src) {
DEBUG("have EOF\n");
playing = FALSE;
}
int main(int argc,char *argv[]) {
GstElement *pipeline;
GstElement *decodethread;
GstElementFactory *srcfactory;
GstElement *src;
GstElementFactory *decodefactory;
GstElement *decode;
GstElementFactory *queuefactory;
GstElement *queue;
GstElement *playthread;
GstElementFactory *sinkfactory;
GstElement *sink;
gst_init(&argc,&argv);
/* first create the main pipeline */
pipeline = gst_pipeline_new("pipeline");
/* then the decode thread, source, and decoder */
decodethread = gst_thread_new("decodethread");
srcfactory = gst_elementfactory_find("asyncdisksrc");
src = gst_elementfactory_create(srcfactory,"src");
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(src));
_gst_plugin_spew = TRUE;
if (argc > 2)
gst_plugin_load(argv[2]);
else
gst_plugin_load_all();
decodefactory = gst_elementfactory_find("mpg123");
decode = gst_elementfactory_create(decodefactory,"decode");
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(decode));
gst_element_add_ghost_pad(GST_ELEMENT(decodethread),
gst_element_get_pad(decode,"src"));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(decode,"sink"));
/* then the play thread and sink */
playthread = gst_thread_new("playthread");
sinkfactory = gst_elementfactory_find("audiosink");
sink = gst_elementfactory_create(sinkfactory,"sink");
gst_bin_add(GST_BIN(playthread),GST_ELEMENT(sink));
gst_element_add_ghost_pad(GST_ELEMENT(playthread),
gst_element_get_pad(sink,"sink"));
/* create the queue */
queuefactory = gst_elementfactory_find("queue");
queue = gst_elementfactory_create(queuefactory,"queue");
/* add threads to the main pipeline */
gst_bin_add(GST_BIN(pipeline),decodethread);
gst_bin_add(GST_BIN(pipeline),queue);
gst_bin_add(GST_BIN(pipeline),playthread);
gst_pad_connect(gst_element_get_pad(decodethread,"src"),
// gst_element_get_pad(queue,"sink"));
// gst_pad_connect(gst_element_get_pad(queue,"src"),
gst_element_get_pad(playthread,"sink"));
gtk_signal_connect(GTK_OBJECT(src),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
g_print("\nsetting up the decode thread to *NOT* thread\n");
// gtk_object_set(GTK_OBJECT(decodethread),"create_thread",TRUE,NULL);
gtk_object_set(GTK_OBJECT(playthread),"create_thread",FALSE,NULL);
g_print("\neverything's built, setting it up to be runnable\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
g_print("\nok, runnable, hitting 'play'...\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
g_print("\niterating on %p and %p\n",decodethread,playthread);
while (playing) {
gst_thread_iterate(GST_THREAD(playthread));
/* buffers got wedged in the queue, unstick them */
// while (((GstQueue *)queue)->buffers_queued)
// gst_connection_push(GST_CONNECTION(queue));
// gst_thread_iterate(GST_THREAD(playthread));
// g_print("stuffed and unstuck the queue\n");
// sleep(1);
}
}

51
test/r.c Normal file
View file

@ -0,0 +1,51 @@
#include <glib.h>
#include <gst/gst.h>
void eof(GstSrc *src) {
g_print("have eof, quitting\n");
exit(0);
}
int main(int argc,char *argv[]) {
GstElement *bin, *disksrc, *audiosink;
GList *padlist;
gst_init(&argc,&argv);
bin = gst_bin_new("bin");
disksrc = gst_disksrc_new("disksrc");
g_print("created disksrc\n");
if (argc == 2)
gst_disksrc_set_filename(disksrc,argv[1]);
else
gst_disksrc_set_filename(disksrc,"mendelssohn.1.raw");
gtk_object_set(GTK_OBJECT(disksrc),"bytesperread",32768,NULL);
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
audiosink = gst_audiosink_new("audiosink");
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
gst_element_get_pad(audiosink,"sink"));
/* set soundcard properties */
gst_audiosink_set_format(GST_AUDIOSINK(audiosink),AFMT_S16_BE);
gst_audiosink_set_channels(GST_AUDIOSINK(audiosink),2);
gst_audiosink_set_frequency(GST_AUDIOSINK(audiosink),44100);
while(1)
gst_disksrc_push(GST_SRC(disksrc));
gst_object_destroy(GST_OBJECT(audiosink));
gst_object_destroy(GST_OBJECT(disksrc));
gst_object_destroy(GST_OBJECT(bin));
}

43
test/record.c Normal file
View file

@ -0,0 +1,43 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <glib.h>
#include <gst/gst.h>
int main(int argc,char *argv[]) {
int fd;
GstElement *pipeline, *audiosrc, *fdsink;
GstElementFactory *audiosrcfactory, *fdsinkfactory;
GList *padlist;
gst_init(&argc,&argv);
pipeline = gst_pipeline_new("pipeline");
audiosrcfactory = gst_elementfactory_find("audiosrc");
audiosrc = gst_elementfactory_create(audiosrcfactory,"audiosrc");
fd = open(argv[1],O_CREAT|O_RDWR);
fdsinkfactory = gst_elementfactory_find("fdsink");
fdsink = gst_elementfactory_create(fdsinkfactory,"fdsink");
gtk_object_set(GTK_OBJECT(fdsink),"fd",fd,NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(audiosrc));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(fdsink));
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(audiosrc,"src"),
gst_element_get_pad(fdsink,"sink"));
g_print("\neverything's built, setting it up to be runnable\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
g_print("\nok, runnable, hitting 'play'...\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
while(1)
gst_src_push(GST_SRC(audiosrc));
}

116
test/s.c Normal file
View file

@ -0,0 +1,116 @@
#include <glib.h>
#include <gst/gst.h>
#include <ghttp.h>
void eof(GstSrc *src) {
g_print("have eof, quitting\n");
exit(0);
}
int main(int argc,char *argv[]) {
guint16 mp3type;
GList *factories;
GstElementFactory *parsefactory;
GstElement *bin, *src, *parse, *audiosink;
GList *padlist;
ghttp_request *pls;
guchar *plsbuf;
gint plsbuflen,parsedlen = 0;
guchar *url,*local;
GSList *urls = NULL;
pls = ghttp_request_new();
if (argc >= 2)
ghttp_set_uri(pls,argv[1]);
else
ghttp_set_uri(pls,"http://209.127.18.4:9000");
ghttp_prepare(pls);
ghttp_process(pls);
plsbuf = ghttp_get_body(pls);
plsbuflen = ghttp_get_body_len(pls);
while (parsedlen < plsbuflen) {
local = plsbuf + parsedlen;
if ((*local != '[') && (*local != '\n')) { /* t/v pair */
if (!strncmp(local,"File1=",4)) { /* if file */
url = strchr(local,'=') + 1; /* url after = */
local = strchr(url,'\n'); /* ffwd after = */
*(local)++ = 0; /* nullz url */
g_print("prepending '%s' to list\n",url);
urls = g_slist_prepend(urls,g_strdup(url));
/* local should point to next line now */
} else {
local = strchr(local,'\n') + 1; /* skip line */
}
} else {
local = strchr(local,'\n') + 1; /* skip line */
}
/* we can consider that line parsed... */
parsedlen = local - plsbuf;
}
if (urls == NULL) {
g_print("couldn't find any streams\n");
exit(1);
}
ghttp_request_destroy(pls);
gst_init(&argc,&argv);
gst_plugin_load_all();
bin = gst_bin_new("bin");
src = gst_httpsrc_new("src");
if (argc == 3) {
int i;
for (i=1;i<atoi(argv[2]);i++)
urls = g_slist_next(urls);
}
g_print("loading shoutcast server %s\n",urls->data);
gtk_object_set(GTK_OBJECT(src),"location",urls->data,NULL);
g_print("created src\n");
/* now it's time to get the parser */
mp3type = gst_type_find_by_mime("audio/mpeg");
factories = gst_type_get_sinks(mp3type);
if (factories != NULL)
parsefactory = GST_ELEMENTFACTORY(factories->data);
else {
g_print("sorry, can't find anyone registered to sink 'mp3'\n");
return 1;
}
parse = gst_elementfactory_create(parsefactory,"parser");
if (parse == NULL) {
g_print("sorry, couldn't create parser\n");
return 1;
}
audiosink = gst_audiosink_new("audiosink");
gtk_signal_connect(GTK_OBJECT(src),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),GST_OBJECT(src));
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
gst_element_get_pad(audiosink,"sink"));
sleep(5); /* to let the network buffer fill a bit */
while(1) {
g_print("calling gst_httpsrc_push\n");
gst_httpsrc_push(GST_SRC(src));
}
gst_object_destroy(GST_OBJECT(audiosink));
gst_object_destroy(GST_OBJECT(parse));
gst_object_destroy(GST_OBJECT(src));
gst_object_destroy(GST_OBJECT(bin));
}

80
test/spectrum.c Normal file
View file

@ -0,0 +1,80 @@
#include <gnome.h>
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
void spectrum_chain(GstPad *pad,GstBuffer *buf);
gboolean idle_func(gpointer data);
GtkWidget *drawingarea;
int main(int argc,char *argv[]) {
GstElement *bin;
GstElementFactory *srcfactory;
GstElement *src;
GstElementFactory *spectrumfactory;
GstElement *spectrum;
GstPad *spectrumpad;
GtkWidget *appwindow;
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
gst_plugin_load("libgstspectrum.so");
gnome_init("Spectrum","0.0.1",argc,argv);
bin = gst_bin_new("bin");
srcfactory = gst_elementfactory_find("audiosrc");
spectrumfactory = gst_elementfactory_find("gstspectrum");
src = gst_elementfactory_create(srcfactory,"src");
gtk_object_set(GTK_OBJECT(src),"bytes_per_read",(gulong)1024,NULL);
spectrum = gst_elementfactory_create(spectrumfactory,"spectrum");
gtk_object_set(GTK_OBJECT(spectrum),"width",256,NULL);
gst_bin_add(GST_BIN(bin),GST_ELEMENT(src));
gst_bin_add(GST_BIN(bin),GST_ELEMENT(spectrum));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(spectrum,"sink"));
spectrumpad = gst_pad_new("sink",GST_PAD_SINK);
gst_pad_set_chain_function(spectrumpad,spectrum_chain);
gst_pad_connect(gst_element_get_pad(spectrum,"src"),spectrumpad);
appwindow = gnome_app_new("spectrum","Spectrum");
drawingarea = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(drawingarea),256,32);
gnome_app_set_contents(GNOME_APP(appwindow),drawingarea);
gtk_widget_show_all(appwindow);
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_RUNNING);
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_PLAYING);
g_idle_add(idle_func,src);
gtk_main();
}
void spectrum_chain(GstPad *pad,GstBuffer *buf) {
gint i,size;
guchar *data = buf->data;
gdk_draw_rectangle(drawingarea->window,drawingarea->style->black_gc,
TRUE,0,0,GST_BUFFER_SIZE(buf),25);
for (i=0;i<GST_BUFFER_SIZE(buf);i++) {
gdk_draw_rectangle(drawingarea->window,drawingarea->style->white_gc,
TRUE,i,32-data[i],1,data[i]);
}
gst_buffer_unref(buf);
}
gboolean idle_func(gpointer data) {
gst_src_push(GST_SRC(data));
return TRUE;
}

75
test/states.c Normal file
View file

@ -0,0 +1,75 @@
#include <glib.h>
#include <gst/gst.h>
int main(int argc,char *argv[]) {
GstBin *bin,
GstElement *src, *identity, *sink;
gst_init(&argc,&argv);
bin = gst_bin_new("bin");
src = gst_disksrc_new("fakesrc");
gst_disksrc_set_filename(src,"demo.mp3");
list_pads(src);
binf = gst_bin_new("binf");
filter1 = gst_fakefilter_new("filter1");
list_pads(filter1);
filter2 = gst_fakefilter_new("filter2");
list_pads(filter2);
sink = gst_fakesink_new("fakesink");
list_pads(sink);
gtk_signal_connect(GTK_OBJECT(bin),"object_added",
GTK_SIGNAL_FUNC(added_child),NULL);
gtk_signal_connect(GTK_OBJECT(binf),"object_added",
GTK_SIGNAL_FUNC(added_child),NULL);
gtk_signal_connect(GTK_OBJECT(binf),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
gtk_signal_connect(GTK_OBJECT(src),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
gtk_signal_connect(GTK_OBJECT(filter1),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
gtk_signal_connect(GTK_OBJECT(filter2),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
gtk_signal_connect(GTK_OBJECT(sink),"parent_set",
GTK_SIGNAL_FUNC(added_parent),NULL);
/* add filter1 to the subbin */
gst_bin_add(GST_BIN(binf),GST_ELEMENT(filter1));
gst_bin_add(GST_BIN(binf),GST_ELEMENT(filter2));
/* connect the two together */
gst_pad_connect(gst_element_get_pad(filter1,"src"),
gst_element_get_pad(filter2,"sink"));
/* export the pads */
gst_element_add_ghost_pad(binf,gst_element_get_pad(filter1,"sink"));
gst_element_add_ghost_pad(binf,gst_element_get_pad(filter2,"src"));
list_pads(binf);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),GST_OBJECT(src));
gst_bin_add(GST_BIN(bin),GST_OBJECT(binf));
gst_bin_add(GST_BIN(bin),GST_OBJECT(sink));
/* connect src to binf */
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(binf,"sink"));
/* connect binf to sink */
gst_pad_connect(gst_element_get_pad(binf,"src"),
gst_element_get_pad(sink,"sink"));
gst_disksrc_push(GST_SRC(src));
gst_object_destroy(GST_OBJECT(src));
gst_object_destroy(GST_OBJECT(filter1));
gst_object_destroy(GST_OBJECT(filter2));
gst_object_destroy(GST_OBJECT(binf));
gst_object_destroy(GST_OBJECT(sink));
gst_object_destroy(GST_OBJECT(bin));
}

69
test/teardown.c Normal file
View file

@ -0,0 +1,69 @@
#include <gst/gst.h>
#include "mem.h"
extern gboolean _gst_plugin_spew;
GstPipeline *teardown_create_pipeline() {
GstPipeline *pipeline;
GstElementFactory *srcfactory, *sinkfactory;
GstElement *src, *sink;
GstPad *srcpad, *sinkpad;
pipeline = gst_pipeline_new("pipeline");
g_return_if_fail(pipeline != NULL);
srcfactory = gst_elementfactory_find("fakesrc");
g_return_if_fail(srcfactory != NULL);
sinkfactory = gst_elementfactory_find("fakesink");
g_return_if_fail(sinkfactory != NULL);
src = gst_elementfactory_create(srcfactory,"src");
g_return_if_fail(src != NULL);
sink = gst_elementfactory_create(sinkfactory,"sink");
g_return_if_fail(sink != NULL);
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(sink));
srcpad = gst_element_get_pad(src,"src");
g_return_if_fail(srcpad != NULL);
sinkpad = gst_element_get_pad(sink,"sink");
g_return_if_fail(srcpad != NULL);
gst_pad_connect(srcpad,sinkpad);
return GST_PIPELINE(pipeline);
}
void teardown_destroy_pipeline(GstPipeline *pipeline) {
gst_element_destroy(pipeline);
}
int main(int argc,char *argv[]) {
GstElement *pipeline, *src;
int i,j,max = 1;
long usage1,usage2;
// _gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
if (argc == 2)
max = atoi(argv[1]);
usage1 = vmsize();
for (i=0;i<max;i++) {
pipeline = teardown_create_pipeline();
src = gst_bin_get_by_name(GST_BIN(pipeline),"src");
// g_print("got source %p, pushing",src);
// for (j=0;j<max;j++) {
// gst_src_push(GST_SRC(src));
// g_print(".");
// }
// g_print("\n");
teardown_destroy_pipeline(pipeline);
}
usage2 = vmsize();
g_print("uses %d bytes\n",usage2-usage1);
}

63
test/typefind.c Normal file
View file

@ -0,0 +1,63 @@
#include <gst/gst.h>
int main(int argc,char *argv[]) {
GstType *mp3type;
GList *factories;
GstElement *src;
GList *padlist;
gst_init(&argc,&argv);
gst_plugin_load_all();
bin = gst_bin_new("bin");
disksrc = gst_disksrc_new("disksrc");
g_print("created disksrc\n");
if (argc == 2)
gst_disksrc_set_filename(disksrc,argv[1]);
else
gst_disksrc_set_filename(disksrc,"Thank_you_very_much.au");
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
/* now it's time to get the parser */
autype = gst_type_get_by_mime("audio/au");
factories = gst_type_get_sinks(autype);
if (factories != NULL)
parsefactory = GST_ELEMENTFACTORY(factories->data);
else {
g_print("sorry, can't find anyone registered to sink 'au'\n");
return 1;
}
parse = gst_elementfactory_create(parsefactory,"parser");
if (parse == NULL) {
g_print("sorry, couldn't create parser\n");
return 1;
}
audiosink = gst_audiosink_new("audiosink");
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
gst_element_get_pad(audiosink,"sink"));
while(1)
gst_disksrc_push(GST_SRC(disksrc));
gst_object_destroy(GST_OBJECT(audiosink));
gst_object_destroy(GST_OBJECT(parse));
gst_object_destroy(GST_OBJECT(disksrc));
gst_object_destroy(GST_OBJECT(bin));
}

44
test/types.c Normal file
View file

@ -0,0 +1,44 @@
#include <glib.h>
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
GstTypeFactory testfactory = { "test/test", ".tst", NULL };
int main(int argc,char *argv[]) {
guint16 id;
GstType *type;
GstElementFactory *element;
GList *types, *elements;
// _gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
// gst_plugin_load_all();
gst_plugin_load("libgstparseau.so");
gst_plugin_load("libgstparsewav.so");
gst_plugin_load("libgstxa.so");
gst_plugin_load("libstereo.so");
gst_plugin_load("libvolume.so");
gst_plugin_load("libsmoothwave.so");
gst_plugin_load("libgstspectrum.so");
gst_plugin_load("libsynaesthesia.so");
gst_plugin_load("libvumeter.so");
id = gst_type_register(&testfactory);
types = gst_type_get_list();
while (types) {
type = (GstType *)types->data;
g_print("%d: have type '%s'\n",type->id,type->mime);
types = g_list_next(types);
}
elements = gst_elementfactory_get_list();
while (elements) {
element = (GstElementFactory *)elements->data;
g_print("%d: have elementfactory '%s': \"%s\"\n",element->type,
element->name,element->details->longname);
elements = g_list_next(elements);
}
}

72
test/w.c Normal file
View file

@ -0,0 +1,72 @@
#include <gst/gst.h>
void eof(GstSrc *src) {
g_print("have eof, quitting\n");
exit(0);
}
int main(int argc,char *argv[]) {
GstType *autype;
GList *factories;
GstElementFactory *parsefactory;
GstElement *bin, *disksrc, *parse, *audiosink;
GList *padlist;
gst_init(&argc,&argv);
gst_plugin_load_all();
bin = gst_bin_new("bin");
disksrc = gst_disksrc_new("disksrc");
g_print("created disksrc\n");
if (argc == 2)
gst_disksrc_set_filename(disksrc,argv[1]);
else
gst_disksrc_set_filename(disksrc,"futile.wav");
// gst_disksrc_set_bytesperread(disksrc,32768);
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
/* now it's time to get the parser */
autype = gst_type_get_by_mime("audio/wav");
factories = gst_type_get_sinks(autype);
if (factories != NULL)
parsefactory = GST_ELEMENTFACTORY(factories->data);
else {
g_print("sorry, can't find anyone registered to sink 'wav'\n");
return 1;
}
parse = gst_elementfactory_create(parsefactory,"parser");
if (parse == NULL) {
g_print("sorry, couldn't create parser\n");
return 1;
}
audiosink = gst_audiosink_new("audiosink");
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
GTK_SIGNAL_FUNC(eof),NULL);
/* add objects to the main pipeline */
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
/* connect src to sink */
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
gst_element_get_pad(parse,"sink"));
gst_pad_connect(gst_element_get_pad(parse,"src"),
gst_element_get_pad(audiosink,"sink"));
while(1) {
g_print("\n");
gst_disksrc_push(GST_SRC(disksrc));
}
gst_object_destroy(GST_OBJECT(audiosink));
gst_object_destroy(GST_OBJECT(parse));
gst_object_destroy(GST_OBJECT(disksrc));
gst_object_destroy(GST_OBJECT(bin));
}

60
test/wave.c Normal file
View file

@ -0,0 +1,60 @@
#include <gnome.h>
#include <gst/gst.h>
extern gboolean _gst_plugin_spew;
gboolean idle_func(gpointer data);
GtkWidget *drawingarea;
int main(int argc,char *argv[]) {
GstElement *bin;
GstElementFactory *srcfactory;
GstElement *src;
GstElementFactory *wavefactory;
GstElement *wave;
GtkWidget *appwindow;
_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
gst_plugin_load("libsmoothwave.so");
gnome_init("Wave","0.0.1",argc,argv);
bin = gst_bin_new("bin");
srcfactory = gst_elementfactory_find("audiosrc");
g_return_if_fail(srcfactory != NULL);
wavefactory = gst_elementfactory_find("smoothwave");
g_return_if_fail(wavefactory != NULL);
src = gst_elementfactory_create(srcfactory,"src");
gtk_object_set(GTK_OBJECT(src),"bytes_per_read",(gulong)2048,NULL);
wave = gst_elementfactory_create(wavefactory,"wave");
gtk_object_set(GTK_OBJECT(wave),"width",256,"height",100,NULL);
gst_bin_add(GST_BIN(bin),GST_ELEMENT(src));
gst_bin_add(GST_BIN(bin),GST_ELEMENT(wave));
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(wave,"sink"));
appwindow = gnome_app_new("wave","Wave");
drawingarea = gtk_drawing_area_new();
gnome_app_set_contents(GNOME_APP(appwindow),gst_util_get_widget_arg(GTK_OBJECT(wave),"widget"));
gtk_widget_show_all(appwindow);
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_RUNNING);
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_PLAYING);
g_idle_add(idle_func,src);
gtk_main();
}
gboolean idle_func(gpointer data) {
gst_src_push(GST_SRC(data));
return TRUE;
}

6
test/xml/Makefile.am Normal file
View file

@ -0,0 +1,6 @@
bin_PROGRAMS = readreg createreg
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) $(XML_CFLAGS) -I$(top_srcdir)
LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(XML_LIBS) $(top_srcdir)/gst/libgst.la
EXTRA_DIST = README registry.xml

62
test/xml/createreg.c Normal file
View file

@ -0,0 +1,62 @@
#include <glib.h>
#include <gnome-xml/parser.h>
#include <gst/gst.h>
typedef struct _GstRegistryPlugin GstRegistryPlugin;
typedef struct _GstRegistryElement GstRegistryElement;
struct _GstRegistryPlugin {
gchar *name;
gchar *filename;
};
struct _GstRegistryElement {
GstRegistryPlugin *plugin;
gchar *name;
GstElementDetails details;
};
int main(int argc,char *argv[]) {
xmlDocPtr doc;
xmlNodePtr tree, subtree;
GList *plugins = NULL, *elements = NULL;
gst_init(&argc,&argv);
gst_plugin_load_all();
doc = xmlNewDoc("1.0");
doc->root = xmlNewDocNode(doc,NULL,"GST-PluginRegistry",NULL);
plugins = gst_plugin_get_list();
while (plugins) {
GstPlugin *plugin = (GstPlugin *)plugins->data;
tree = xmlNewChild(doc->root,NULL,"plugin",NULL);
subtree = xmlNewChild(tree,NULL,"name",plugin->name);
subtree = xmlNewChild(tree,NULL,"longname",plugin->longname);
subtree = xmlNewChild(tree,NULL,"filename",plugin->filename);
elements = plugin->elements;
while (elements) {
GstElementFactory *element = (GstElementFactory *)elements->data;
tree = xmlNewChild(doc->root,NULL,"element",NULL);
subtree = xmlNewChild(tree,NULL,"plugin",plugin->name);
subtree = xmlNewChild(tree,NULL,"name",element->name);
subtree = xmlNewChild(tree,NULL,"longname",
element->details->longname);
subtree = xmlNewChild(tree,NULL,"class",
element->details->class);
subtree = xmlNewChild(tree,NULL,"description",
element->details->description);
subtree = xmlNewChild(tree,NULL,"version",
element->details->version);
subtree = xmlNewChild(tree,NULL,"author",
element->details->author);
subtree = xmlNewChild(tree,NULL,"copyright",
element->details->copyright);
elements = g_list_next(elements);
}
plugins = g_list_next(plugins);
}
xmlSaveFile("newreg.xml",doc);
exit(0);
}

126
test/xml/readreg.c Normal file
View file

@ -0,0 +1,126 @@
#include <glib.h>
#include <gnome-xml/parser.h>
#include <gst/gst.h>
typedef struct _GstRegistryPlugin GstRegistryPlugin;
typedef struct _GstRegistryElement GstRegistryElement;
struct _GstRegistryPlugin {
gchar *name;
gchar *filename;
};
struct _GstRegistryElement {
GstRegistryPlugin *plugin;
gchar *name;
GstElementDetails details;
};
gchar *getcontents(xmlDocPtr doc,xmlNodePtr cur) {
return g_strdup(xmlNodeListGetString(doc,cur->childs,1));
}
int main(int argc,char *argv[]) {
xmlDocPtr doc;
xmlNodePtr cur;
int i;
GSList *plugins = NULL, *elements = NULL;
// gst_init(&argc,&argv);
doc = xmlParseFile("registry.xml");
g_assert(doc != NULL);
cur = doc->root;
if (cur == NULL) {
g_print("registry is empty\n");
xmlFreeDoc(doc);
exit(0);
}
if (strcmp(cur->name,"GST-PluginRegistry")) {
g_print("document not the right type\n");
xmlFreeDoc(doc);
exit(1);
}
cur = cur->childs; /* 'childs'??? He (Daniel) is Dutch, so... */
while (cur != NULL) {
if (!strcmp(cur->name,"plugin")) {
xmlNodePtr field = cur->childs;
GstRegistryPlugin *plugin = g_new0(GstRegistryPlugin,1);
while (field) {
if (!strcmp(field->name,"name"))
plugin->name = getcontents(doc,field);
else if (!strcmp(field->name,"filename"))
plugin->filename = getcontents(doc,field);
field = field->next;
}
g_print("new plugin '%s' at '%s'\n",plugin->name,plugin->filename);
plugins = g_slist_prepend(plugins,plugin);
} else if (!strcmp(cur->name,"element")) {
xmlNodePtr field = cur->childs;
GstRegistryElement *element = g_new0(GstRegistryElement,1);
while (field) {
if (!strcmp(field->name,"plugin")) {
gchar *pluginname = getcontents(doc,field);
GSList *list = plugins;
element->plugin = NULL;
while (list) {
GstRegistryPlugin *plugin = (GstRegistryPlugin *)list->data;
if (!strcmp(pluginname,plugin->name)) {
element->plugin = plugin;
break;
}
list = g_slist_next(list);
}
} else if (!strcmp(field->name,"name"))
element->name = getcontents(doc,field);
else if (!strcmp(field->name,"longname"))
element->details.longname = getcontents(doc,field);
else if (!strcmp(field->name,"class"))
element->details.class = getcontents(doc,field);
else if (!strcmp(field->name,"description"))
element->details.description = getcontents(doc,field);
else if (!strcmp(field->name,"version"))
element->details.version = getcontents(doc,field);
else if (!strcmp(field->name,"author"))
element->details.author = getcontents(doc,field);
else if (!strcmp(field->name,"copyright"))
element->details.copyright = getcontents(doc,field);
field = field->next;
}
g_print("new element '%s'in '%s'\n",element->name,element->plugin->name);
elements = g_slist_prepend(elements,element);
}
cur = cur->next;
}
for (i=1;i<argc;i++) {
GSList *list;
g_print("searching for element '%s'\n",argv[i]);
list = elements;
while (list) {
GstRegistryElement *element = (GstRegistryElement *)list->data;
// g_print("comparing against '%s'\n",element->name);
if (!strcmp(argv[i],element->name)) {
g_print("Plugin name: %s\n",element->plugin->name);
g_print("Plugin filename: %s\n",element->plugin->filename);
g_print("Element name: %s\n",element->name);
g_print("Element long name: %s\n",element->details.longname);
g_print("Element class: %s\n",element->details.class);
g_print("Element description: %s\n",element->details.description);
g_print("Element version: %s\n",element->details.version);
g_print("Element author: %s\n",element->details.author);
g_print("Element copyright: %s\n",element->details.copyright);
// gst_plugin_load_absolute(element->plugin->filename);
}
list = g_slist_next(list);
}
}
exit(0);
}

4
tools/Makefile.am Normal file
View file

@ -0,0 +1,4 @@
bin_PROGRAMS = launch
LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) -I$(top_srcdir)

16
tools/README Normal file
View file

@ -0,0 +1,16 @@
launch
======
This is a tool that will construct pipelines based on a command-line
syntax. The syntax is rather complex to enable all the features I want it
to have, but should be easy to use for most people. Multi-pathed and
feedback pipelines are the most complex.
A simple commandline looks like:
./launch disksrc demo.mp3 | mp3parse | mpg123 | audiosink-oss
A more complex pipeline looks like:
./launch disksrc redpill.vob | css-descramble | private_stream_1.0| \
(ac3parse | ac3dec | audioink-oss) video_0| (mpeg2dec | videosink)

115
tools/launch.c Normal file
View file

@ -0,0 +1,115 @@
#include <glib.h>
#include <gst/gst.h>
typedef struct _launch_delayed_pad launch_delayed_pad;
struct _launch_delayed_pad {
gchar *name;
GstPad *peer;
};
void launch_newpad(GstElement *element,GstPad *pad,launch_delayed_pad *peer) {
gst_info("have NEW_PAD signal\n");
// if it matches, connect it
if (!strcmp(gst_pad_get_name(pad),peer->name)) {
gst_pad_connect(pad,peer->peer);
gst_info("delayed connect of '%s' to '%s'\n",
gst_pad_get_name(pad),gst_pad_get_name(peer->peer));
}
}
gint parse(int argc,char *argv[],GstElement *parent,gint offset,gchar endchar) {
gint i = offset;
gchar *plugin;
GstElement *element, *prevelement;
GstPad *prevpad,*nextpad;
gchar *prevpadname = NULL,*nextpadname = NULL;
gchar *ptr;
gint len;
launch_delayed_pad *delayed;
gst_info("at offset %d, argc is %d\n",i,argc);
// loop through all the arguments
while (i < argc) {
// first is the plugin name
plugin = argv[i++];
gst_info("plugin is \"%s\"\n",plugin);
// record previous element
prevelement = element;
// create the element and add it to the parent
element = gst_elementfactory_make(plugin,plugin);
gst_bin_add(GST_BIN(parent),element);
// connect it to the previous if there is one
if (nextpadname != NULL) {
// grab the pad of this element
nextpad = gst_element_get_pad(element,nextpadname);
g_return_if_fail(nextpad != NULL);
// check to see if the pad exists yet, connect it if it does
if (prevpad != NULL) {
gst_pad_connect(prevpad,nextpad);
gst_info("wired '%s' to '%s'\n",
gst_pad_get_name(prevpad),gst_pad_get_name(nextpad));
}
// otherwise we have to attach and wait for it to show
else {
delayed = g_new0(launch_delayed_pad,1);
delayed->name = prevpadname;
delayed->peer = nextpad;
gtk_signal_connect(GTK_OBJECT(prevelement),"new_pad",
launch_newpad,delayed);
}
}
// then come all the other things
while (i < argc) {
// snag the length in advance;
len = strlen(argv[i]);
// if it's just a connection, pick the 'src' pad and move on
if (ptr = strchr(argv[i],'|')) {
// if there's a previous pad name
if (ptr != argv[i]) {
ptr[0] = '\0';
prevpadname = argv[i];
prevpad = gst_element_get_pad(element,prevpadname);
} else
prevpad = gst_element_get_pad(element,"src");
// if there's a next pad name
if (((ptr - argv[i]) + 1) < len) {
nextpadname = ptr + 1;
} else
nextpadname = "sink";
i++;
break;
} else {
gst_info("have unknown argument '%s'\n",argv[i]);
gtk_object_set(GTK_OBJECT(element),"location",argv[i],NULL);
i++;
}
}
}
}
int main(int argc,char *argv[]) {
int t;
GstElement *pipeline;
gst_init(&argc,&argv);
gst_plugin_load_all();
gst_info("\n\n");
pipeline = gst_elementfactory_make("thread","launch");
if (t = atoi(argv[1]))
parse(argc,argv,pipeline,2,0);
else
parse(argc,argv,pipeline,1,0);
xmlSaveFile("launch.xml",gst_xml_write(pipeline));
gst_element_set_state(pipeline,GST_STATE_RUNNING);
gst_element_set_state(pipeline,GST_STATE_PLAYING);
if (t)
sleep(t);
else
sleep(5);
}