summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Walthinsen <omega@temple-baptist.org>2000-01-30 10:44:33 +0000
committerErik Walthinsen <omega@temple-baptist.org>2000-01-30 10:44:33 +0000
commit0ec400890cca169763f5d26446bc048279c1630f (patch)
tree6a7a132ed5aee76bcae214fe2acb675ec607b0eb
parent1762dfbf982a75d895676b0063379e33b4f9b96a (diff)
initial checkin
Original commit message from CVS: initial checkin
-rw-r--r--docs/Makefile.am1
-rw-r--r--docs/random/arch78
-rw-r--r--docs/random/buffers15
-rw-r--r--docs/random/coroutines5
-rw-r--r--docs/random/design12
-rw-r--r--docs/random/example104
-rw-r--r--docs/random/factoryinfo7
-rw-r--r--docs/random/gboolean4
-rw-r--r--docs/random/intro17
-rw-r--r--docs/random/metadata77
-rw-r--r--docs/random/mutability30
-rw-r--r--docs/random/padarch14
-rw-r--r--docs/random/sequence15
-rw-r--r--docs/random/state-transitions45
-rw-r--r--docs/random/states71
-rw-r--r--docs/random/states.old80
-rw-r--r--docs/random/types33
-rw-r--r--docs/random/vis-transform78
-rw-r--r--docs/random/walkthrough39
-rw-r--r--docs/slides/README4
-rw-r--r--docs/slides/abstract9
-rw-r--r--docs/slides/abstract.save10
-rw-r--r--docs/slides/outline144
-rw-r--r--docs/slides/slides17
-rw-r--r--editor/Makefile.am32
-rw-r--r--editor/editor.c49
-rw-r--r--editor/editor.glade74
-rw-r--r--editor/editorelement.glade143
-rw-r--r--editor/gsteditor.c144
-rw-r--r--editor/gsteditor.h360
-rw-r--r--editor/gsteditorbin.c266
-rw-r--r--editor/gsteditorcanvas.c251
-rw-r--r--editor/gsteditorconnection.c289
-rw-r--r--editor/gsteditorconnection.h61
-rw-r--r--editor/gsteditorcreate.c57
-rw-r--r--editor/gsteditorcreate.h24
-rw-r--r--editor/gsteditorelement.c927
-rw-r--r--editor/gsteditorpad.c406
-rw-r--r--editor/gsteditorpad.h79
-rw-r--r--editor/gstelementselect.c278
-rw-r--r--editor/gstelementselect.h23
-rw-r--r--gst/xml/Makefile.am5
-rw-r--r--gst/xml/notes6
-rw-r--r--gst/xml/save.c43
-rw-r--r--test/Makefile.am21
-rw-r--r--test/a.c69
-rw-r--r--test/ac3parse.c55
-rw-r--r--test/ac3play.c84
-rw-r--r--test/ac3sync.c24
-rw-r--r--test/args.c20
-rw-r--r--test/basic.c109
-rw-r--r--test/bindings/Makefile.am11
-rw-r--r--test/bindings/dummy.c20
-rw-r--r--test/bindings/dummy.h19
-rw-r--r--test/bindings/test.c11
-rw-r--r--test/buffer.c53
-rw-r--r--test/cobin.c42
-rw-r--r--test/cothreads/Makefile.am5
-rw-r--r--test/cothreads/cothreads.c143
-rw-r--r--test/cothreads/cothreads.h48
-rw-r--r--test/cothreads/looper.c47
-rw-r--r--test/cothreads/looper.h18
-rw-r--r--test/cothreads/object.c78
-rw-r--r--test/cothreads/object.h30
-rw-r--r--test/cothreads/simple.c23
-rw-r--r--test/cothreads/test.c17
-rw-r--r--test/dvdcat.c46
-rw-r--r--test/fake.c37
-rw-r--r--test/gsttracedump.c15
-rw-r--r--test/jitter.c26
-rw-r--r--test/m.c76
-rw-r--r--test/mcut.c77
-rw-r--r--test/mem.c22
-rw-r--r--test/mem.h1
-rw-r--r--test/mp3.c63
-rw-r--r--test/mp3parse.c55
-rw-r--r--test/mp3play.c59
-rw-r--r--test/mpeg2parse.c95
-rw-r--r--test/mpg123.c67
-rw-r--r--test/p.c55
-rw-r--r--test/plugin.c17
-rw-r--r--test/push.c78
-rw-r--r--test/qtest.c104
-rw-r--r--test/r.c51
-rw-r--r--test/record.c43
-rw-r--r--test/s.c116
-rw-r--r--test/spectrum.c80
-rw-r--r--test/states.c75
-rw-r--r--test/teardown.c69
-rw-r--r--test/typefind.c63
-rw-r--r--test/types.c44
-rw-r--r--test/w.c72
-rw-r--r--test/wave.c60
-rw-r--r--test/xml/Makefile.am6
-rw-r--r--test/xml/createreg.c62
-rw-r--r--test/xml/readreg.c126
-rw-r--r--tools/Makefile.am4
-rw-r--r--tools/README16
-rw-r--r--tools/launch.c115
99 files changed, 7268 insertions, 0 deletions
diff --git a/docs/Makefile.am b/docs/Makefile.am
new file mode 100644
index 000000000..e9a72e904
--- /dev/null
+++ b/docs/Makefile.am
@@ -0,0 +1 @@
+#EXTRA_DIST = random slides
diff --git a/docs/random/arch b/docs/random/arch
new file mode 100644
index 000000000..ba7e88a7c
--- /dev/null
+++ b/docs/random/arch
@@ -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.
diff --git a/docs/random/buffers b/docs/random/buffers
new file mode 100644
index 000000000..dd657d921
--- /dev/null
+++ b/docs/random/buffers
@@ -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
diff --git a/docs/random/coroutines b/docs/random/coroutines
new file mode 100644
index 000000000..d4e677bc3
--- /dev/null
+++ b/docs/random/coroutines
@@ -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)
diff --git a/docs/random/design b/docs/random/design
new file mode 100644
index 000000000..24b1d5fed
--- /dev/null
+++ b/docs/random/design
@@ -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.
+
+
diff --git a/docs/random/example b/docs/random/example
new file mode 100644
index 000000000..0bb166b60
--- /dev/null
+++ b/docs/random/example
@@ -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");
diff --git a/docs/random/factoryinfo b/docs/random/factoryinfo
new file mode 100644
index 000000000..9a5888804
--- /dev/null
+++ b/docs/random/factoryinfo
@@ -0,0 +1,7 @@
+short name
+class
+long name
+descripion
+author
+version
+copyright
diff --git a/docs/random/gboolean b/docs/random/gboolean
new file mode 100644
index 000000000..866cb6f39
--- /dev/null
+++ b/docs/random/gboolean
@@ -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.
diff --git a/docs/random/intro b/docs/random/intro
new file mode 100644
index 000000000..d305d5357
--- /dev/null
+++ b/docs/random/intro
@@ -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.
+
+
diff --git a/docs/random/metadata b/docs/random/metadata
new file mode 100644
index 000000000..afe0a754f
--- /dev/null
+++ b/docs/random/metadata
@@ -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?
diff --git a/docs/random/mutability b/docs/random/mutability
new file mode 100644
index 000000000..74a094449
--- /dev/null
+++ b/docs/random/mutability
@@ -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
diff --git a/docs/random/padarch b/docs/random/padarch
new file mode 100644
index 000000000..3ceed6de5
--- /dev/null
+++ b/docs/random/padarch
@@ -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
diff --git a/docs/random/sequence b/docs/random/sequence
new file mode 100644
index 000000000..51810d11d
--- /dev/null
+++ b/docs/random/sequence
@@ -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");
+
diff --git a/docs/random/state-transitions b/docs/random/state-transitions
new file mode 100644
index 000000000..4752afec8
--- /dev/null
+++ b/docs/random/state-transitions
@@ -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
diff --git a/docs/random/states b/docs/random/states
new file mode 100644
index 000000000..ef05903b3
--- /dev/null
+++ b/docs/random/states
@@ -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.
diff --git a/docs/random/states.old b/docs/random/states.old
new file mode 100644
index 000000000..74d7de163
--- /dev/null
+++ b/docs/random/states.old
@@ -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
diff --git a/docs/random/types b/docs/random/types
new file mode 100644
index 000000000..0a14f8f62
--- /dev/null
+++ b/docs/random/types
@@ -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.
diff --git a/docs/random/vis-transform b/docs/random/vis-transform
new file mode 100644
index 000000000..a83e7c01d
--- /dev/null
+++ b/docs/random/vis-transform
@@ -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.
diff --git a/docs/random/walkthrough b/docs/random/walkthrough
new file mode 100644
index 000000000..f6b21fad8
--- /dev/null
+++ b/docs/random/walkthrough
@@ -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.
diff --git a/docs/slides/README b/docs/slides/README
new file mode 100644
index 000000000..923e6dc5a
--- /dev/null
+++ b/docs/slides/README
@@ -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.
diff --git a/docs/slides/abstract b/docs/slides/abstract
new file mode 100644
index 000000000..b4bc016b5
--- /dev/null
+++ b/docs/slides/abstract
@@ -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.
diff --git a/docs/slides/abstract.save b/docs/slides/abstract.save
new file mode 100644
index 000000000..b317c5a66
--- /dev/null
+++ b/docs/slides/abstract.save
@@ -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.
+
diff --git a/docs/slides/outline b/docs/slides/outline
new file mode 100644
index 000000000..5808dbb01
--- /dev/null
+++ b/docs/slides/outline
@@ -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)
diff --git a/docs/slides/slides b/docs/slides/slides
new file mode 100644
index 000000000..b43481159
--- /dev/null
+++ b/docs/slides/slides
@@ -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
diff --git a/editor/Makefile.am b/editor/Makefile.am
new file mode 100644
index 000000000..394cf839c
--- /dev/null
+++ b/editor/Makefile.am
@@ -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
diff --git a/editor/editor.c b/editor/editor.c
new file mode 100644
index 000000000..a16a0f254
--- /dev/null
+++ b/editor/editor.c
@@ -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);
+}
diff --git a/editor/editor.glade b/editor/editor.glade
new file mode 100644
index 000000000..2f4c60acf
--- /dev/null
+++ b/editor/editor.glade
@@ -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>
diff --git a/editor/editorelement.glade b/editor/editorelement.glade
new file mode 100644
index 000000000..5711e0191
--- /dev/null
+++ b/editor/editorelement.glade
@@ -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>
diff --git a/editor/gsteditor.c b/editor/gsteditor.c
new file mode 100644
index 000000000..62f4eee39
--- /dev/null
+++ b/editor/gsteditor.c
@@ -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;
+ }
+}
diff --git a/editor/gsteditor.h b/editor/gsteditor.h
new file mode 100644
index 000000000..4bc04e123
--- /dev/null
+++ b/editor/gsteditor.h
@@ -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__ */
diff --git a/editor/gsteditorbin.c b/editor/gsteditorbin.c
new file mode 100644
index 000000000..44ebeab87
--- /dev/null
+++ b/editor/gsteditorbin.c
@@ -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);
+}
diff --git a/editor/gsteditorcanvas.c b/editor/gsteditorcanvas.c
new file mode 100644
index 000000000..76b4600e7
--- /dev/null
+++ b/editor/gsteditorcanvas.c
@@ -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;
+}
diff --git a/editor/gsteditorconnection.c b/editor/gsteditorconnection.c
new file mode 100644
index 000000000..dbe4147dc
--- /dev/null
+++ b/editor/gsteditorconnection.c
@@ -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);
+ }
+}
diff --git a/editor/gsteditorconnection.h b/editor/gsteditorconnection.h
new file mode 100644
index 000000000..011edd3a8
--- /dev/null
+++ b/editor/gsteditorconnection.h
@@ -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__ */
diff --git a/editor/gsteditorcreate.c b/editor/gsteditorcreate.c
new file mode 100644
index 000000000..bfadd83d4
--- /dev/null
+++ b/editor/gsteditorcreate.c
@@ -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;
+}
diff --git a/editor/gsteditorcreate.h b/editor/gsteditorcreate.h
new file mode 100644
index 000000000..448de9157
--- /dev/null
+++ b/editor/gsteditorcreate.h
@@ -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);
diff --git a/editor/gsteditorelement.c b/editor/gsteditorelement.c
new file mode 100644
index 000000000..d13c40f4a
--- /dev/null
+++ b/editor/gsteditorelement.c
@@ -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);
+ }
+}
diff --git a/editor/gsteditorpad.c b/editor/gsteditorpad.c
new file mode 100644
index 000000000..9aea1f6c2
--- /dev/null
+++ b/editor/gsteditorpad.c
@@ -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;
+}
diff --git a/editor/gsteditorpad.h b/editor/gsteditorpad.h
new file mode 100644
index 000000000..ed3f8ef82
--- /dev/null
+++ b/editor/gsteditorpad.h
@@ -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__ */
diff --git a/editor/gstelementselect.c b/editor/gstelementselect.c
new file mode 100644
index 000000000..e467b9cd2
--- /dev/null
+++ b/editor/gstelementselect.c
@@ -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 */
diff --git a/editor/gstelementselect.h b/editor/gstelementselect.h
new file mode 100644
index 000000000..65ad3ed5f
--- /dev/null
+++ b/editor/gstelementselect.h
@@ -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();
diff --git a/gst/xml/Makefile.am b/gst/xml/Makefile.am
new file mode 100644
index 000000000..bff38573a
--- /dev/null
+++ b/gst/xml/Makefile.am
@@ -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
+
diff --git a/gst/xml/notes b/gst/xml/notes
new file mode 100644
index 000000000..5ed0566da
--- /dev/null
+++ b/gst/xml/notes
@@ -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.
diff --git a/gst/xml/save.c b/gst/xml/save.c
new file mode 100644
index 000000000..5e41244a1
--- /dev/null
+++ b/gst/xml/save.c
@@ -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);
+}
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 000000000..50c6b26f5
--- /dev/null
+++ b/test/Makefile.am
@@ -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
diff --git a/test/a.c b/test/a.c
new file mode 100644
index 000000000..59ad5d6a5
--- /dev/null
+++ b/test/a.c
@@ -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));
+}
+
diff --git a/test/ac3parse.c b/test/ac3parse.c
new file mode 100644
index 000000000..e018dc864
--- /dev/null
+++ b/test/ac3parse.c
@@ -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));
+}
diff --git a/test/ac3play.c b/test/ac3play.c
new file mode 100644
index 000000000..24e18e3e7
--- /dev/null
+++ b/test/ac3play.c
@@ -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)));
+}
diff --git a/test/ac3sync.c b/test/ac3sync.c
new file mode 100644
index 000000000..67e79dd66
--- /dev/null
+++ b/test/ac3sync.c
@@ -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;
+ }
+}
diff --git a/test/args.c b/test/args.c
new file mode 100644
index 000000000..751a7af70
--- /dev/null
+++ b/test/args.c
@@ -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));
+}
+
diff --git a/test/basic.c b/test/basic.c
new file mode 100644
index 000000000..bb6d65972
--- /dev/null
+++ b/test/basic.c
@@ -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));
+}
+
diff --git a/test/bindings/Makefile.am b/test/bindings/Makefile.am
new file mode 100644
index 000000000..1f7486113
--- /dev/null
+++ b/test/bindings/Makefile.am
@@ -0,0 +1,11 @@
+lib_LTLIBRARIES = libcrashtest.la
+
+libcrashtest_la_SOURCES = \
+ dummy.c
+
+include_HEADERS = \
+ dummy.h
+
+bin_PROGRAMS = test
+
+test_LDADD = libcrashtest.la
diff --git a/test/bindings/dummy.c b/test/bindings/dummy.c
new file mode 100644
index 000000000..0172eb449
--- /dev/null
+++ b/test/bindings/dummy.c
@@ -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;
+}
diff --git a/test/bindings/dummy.h b/test/bindings/dummy.h
new file mode 100644
index 000000000..7b8ad841d
--- /dev/null
+++ b/test/bindings/dummy.h
@@ -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__ */
diff --git a/test/bindings/test.c b/test/bindings/test.c
new file mode 100644
index 000000000..75dc3f2e1
--- /dev/null
+++ b/test/bindings/test.c
@@ -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);
+}
diff --git a/test/buffer.c b/test/buffer.c
new file mode 100644
index 000000000..baeaa347a
--- /dev/null
+++ b/test/buffer.c
@@ -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());
+}
diff --git a/test/cobin.c b/test/cobin.c
new file mode 100644
index 000000000..7f9630959
--- /dev/null
+++ b/test/cobin.c
@@ -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");
+}
diff --git a/test/cothreads/Makefile.am b/test/cothreads/Makefile.am
new file mode 100644
index 000000000..f60104e51
--- /dev/null
+++ b/test/cothreads/Makefile.am
@@ -0,0 +1,5 @@
+bin_PROGRAMS = test simple
+
+test_SOURCES = test.c cothreads.c object.c looper.c
+
+simple_SOURCES = simple.c cothreads.c
diff --git a/test/cothreads/cothreads.c b/test/cothreads/cothreads.c
new file mode 100644
index 000000000..8b12b6708
--- /dev/null
+++ b/test/cothreads/cothreads.c
@@ -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));
+ }
+}
diff --git a/test/cothreads/cothreads.h b/test/cothreads/cothreads.h
new file mode 100644
index 000000000..63fef4290
--- /dev/null
+++ b/test/cothreads/cothreads.h
@@ -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__ */
diff --git a/test/cothreads/looper.c b/test/cothreads/looper.c
new file mode 100644
index 000000000..5b67a019f
--- /dev/null
+++ b/test/cothreads/looper.c
@@ -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);
+ }
+ }
+}
diff --git a/test/cothreads/looper.h b/test/cothreads/looper.h
new file mode 100644
index 000000000..397f91bab
--- /dev/null
+++ b/test/cothreads/looper.h
@@ -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__ */
diff --git a/test/cothreads/object.c b/test/cothreads/object.c
new file mode 100644
index 000000000..2b03e69db
--- /dev/null
+++ b/test/cothreads/object.c
@@ -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");
+}
diff --git a/test/cothreads/object.h b/test/cothreads/object.h
new file mode 100644
index 000000000..9b4ebb6b6
--- /dev/null
+++ b/test/cothreads/object.h
@@ -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__ */
diff --git a/test/cothreads/simple.c b/test/cothreads/simple.c
new file mode 100644
index 000000000..3e1e950de
--- /dev/null
+++ b/test/cothreads/simple.c
@@ -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;
+}
diff --git a/test/cothreads/test.c b/test/cothreads/test.c
new file mode 100644
index 000000000..42934ac0b
--- /dev/null
+++ b/test/cothreads/test.c
@@ -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);
+}
diff --git a/test/dvdcat.c b/test/dvdcat.c
new file mode 100644
index 000000000..4e712e7fa
--- /dev/null
+++ b/test/dvdcat.c
@@ -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));
+}
diff --git a/test/fake.c b/test/fake.c
new file mode 100644
index 000000000..794e22e04
--- /dev/null
+++ b/test/fake.c
@@ -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);
+}
diff --git a/test/gsttracedump.c b/test/gsttracedump.c
new file mode 100644
index 000000000..f5159bb14
--- /dev/null
+++ b/test/gsttracedump.c
@@ -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);
+}
diff --git a/test/jitter.c b/test/jitter.c
new file mode 100644
index 000000000..8d66064e1
--- /dev/null
+++ b/test/jitter.c
@@ -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);
+}
diff --git a/test/m.c b/test/m.c
new file mode 100644
index 000000000..f210e068e
--- /dev/null
+++ b/test/m.c
@@ -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));
+}
+
diff --git a/test/mcut.c b/test/mcut.c
new file mode 100644
index 000000000..95f1969e4
--- /dev/null
+++ b/test/mcut.c
@@ -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));
+}
+
diff --git a/test/mem.c b/test/mem.c
new file mode 100644
index 000000000..8e1c573bd
--- /dev/null
+++ b/test/mem.c
@@ -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;
+}
diff --git a/test/mem.h b/test/mem.h
new file mode 100644
index 000000000..28999db2c
--- /dev/null
+++ b/test/mem.h
@@ -0,0 +1 @@
+int vmsize();
diff --git a/test/mp3.c b/test/mp3.c
new file mode 100644
index 000000000..1fd09e492
--- /dev/null
+++ b/test/mp3.c
@@ -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));
+}
diff --git a/test/mp3parse.c b/test/mp3parse.c
new file mode 100644
index 000000000..284601f59
--- /dev/null
+++ b/test/mp3parse.c
@@ -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));
+}
diff --git a/test/mp3play.c b/test/mp3play.c
new file mode 100644
index 000000000..4f0080769
--- /dev/null
+++ b/test/mp3play.c
@@ -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));
+}
diff --git a/test/mpeg2parse.c b/test/mpeg2parse.c
new file mode 100644
index 000000000..fa3c63373
--- /dev/null
+++ b/test/mpeg2parse.c
@@ -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));
+ }
+}
diff --git a/test/mpg123.c b/test/mpg123.c
new file mode 100644
index 000000000..e242b9c8e
--- /dev/null
+++ b/test/mpg123.c
@@ -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));
+}
+
diff --git a/test/p.c b/test/p.c
new file mode 100644
index 000000000..457e4b374
--- /dev/null
+++ b/test/p.c
@@ -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));
+}
+
diff --git a/test/plugin.c b/test/plugin.c
new file mode 100644
index 000000000..4da003fea
--- /dev/null
+++ b/test/plugin.c
@@ -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)));
+}
diff --git a/test/push.c b/test/push.c
new file mode 100644
index 000000000..7af0ea22a
--- /dev/null
+++ b/test/push.c
@@ -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);
+}
diff --git a/test/qtest.c b/test/qtest.c
new file mode 100644
index 000000000..e7c2d5218
--- /dev/null
+++ b/test/qtest.c
@@ -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);
+ }
+}
diff --git a/test/r.c b/test/r.c
new file mode 100644
index 000000000..5acc6225f
--- /dev/null
+++ b/test/r.c
@@ -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));
+}
+
diff --git a/test/record.c b/test/record.c
new file mode 100644
index 000000000..fe5b96c35
--- /dev/null
+++ b/test/record.c
@@ -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));
+}
+
diff --git a/test/s.c b/test/s.c
new file mode 100644
index 000000000..cefab58e4
--- /dev/null
+++ b/test/s.c
@@ -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));
+}
+
diff --git a/test/spectrum.c b/test/spectrum.c
new file mode 100644
index 000000000..190157c0d
--- /dev/null
+++ b/test/spectrum.c
@@ -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;
+}
diff --git a/test/states.c b/test/states.c
new file mode 100644
index 000000000..e16c16172
--- /dev/null
+++ b/test/states.c
@@ -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));
+}
+
diff --git a/test/teardown.c b/test/teardown.c
new file mode 100644
index 000000000..bdd68283f
--- /dev/null
+++ b/test/teardown.c
@@ -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);
+}
diff --git a/test/typefind.c b/test/typefind.c
new file mode 100644
index 000000000..a9867c6b0
--- /dev/null
+++ b/test/typefind.c
@@ -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));
+}
+
diff --git a/test/types.c b/test/types.c
new file mode 100644
index 000000000..7b003273d
--- /dev/null
+++ b/test/types.c
@@ -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);
+ }
+}
diff --git a/test/w.c b/test/w.c
new file mode 100644
index 000000000..1173e9e95
--- /dev/null
+++ b/test/w.c
@@ -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));
+}
+
diff --git a/test/wave.c b/test/wave.c
new file mode 100644
index 000000000..0aae79906
--- /dev/null
+++ b/test/wave.c
@@ -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;
+}
diff --git a/test/xml/Makefile.am b/test/xml/Makefile.am
new file mode 100644
index 000000000..59c91ed89
--- /dev/null
+++ b/test/xml/Makefile.am
@@ -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
diff --git a/test/xml/createreg.c b/test/xml/createreg.c
new file mode 100644
index 000000000..fc93c7607
--- /dev/null
+++ b/test/xml/createreg.c
@@ -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);
+}
diff --git a/test/xml/readreg.c b/test/xml/readreg.c
new file mode 100644
index 000000000..6e2d46f79
--- /dev/null
+++ b/test/xml/readreg.c
@@ -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);
+}
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 000000000..d79c8bf84
--- /dev/null
+++ b/tools/Makefile.am
@@ -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)
diff --git a/tools/README b/tools/README
new file mode 100644
index 000000000..5d9ffe8fa
--- /dev/null
+++ b/tools/README
@@ -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)
diff --git a/tools/launch.c b/tools/launch.c
new file mode 100644
index 000000000..7be7f2cf8
--- /dev/null
+++ b/tools/launch.c
@@ -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);
+}