mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-25 03:01:03 +00:00
initial checkin
Original commit message from CVS: initial checkin
This commit is contained in:
parent
1762dfbf98
commit
0ec400890c
99 changed files with 7268 additions and 0 deletions
1
docs/Makefile.am
Normal file
1
docs/Makefile.am
Normal file
|
@ -0,0 +1 @@
|
|||
#EXTRA_DIST = random slides
|
78
docs/random/arch
Normal file
78
docs/random/arch
Normal file
|
@ -0,0 +1,78 @@
|
|||
GstElementFactory:
|
||||
|
||||
Base class for all elementfactories. Is a single-instance (per program)
|
||||
object that creates objects of the associated GstElement derivative.
|
||||
|
||||
|
||||
GstPlugin:
|
||||
|
||||
Defines a given plugin. Records plugin name, function pointers, details,
|
||||
etc. Includes a list of GstElementFactories that are associated with
|
||||
this plugin.
|
||||
|
||||
|
||||
|
||||
GstBuffer
|
||||
GstPad
|
||||
GstObject
|
||||
GstSrc
|
||||
GstDiskSrc
|
||||
GstHTTPSrc
|
||||
*
|
||||
GstAsyncSrc
|
||||
GstAsyncDiskSrc
|
||||
*
|
||||
GstFilter
|
||||
GstVideoFilter
|
||||
GstVideoMPEG
|
||||
*
|
||||
GstAudioFilter
|
||||
GstAudioMPEG
|
||||
*
|
||||
*
|
||||
GstSink
|
||||
GstAudioSink
|
||||
GstAudioOSSSink
|
||||
GstAudioALSASink
|
||||
GstAudioESDSink
|
||||
*
|
||||
GstVideoSink
|
||||
GstVideoGDKRGBSink
|
||||
GstVideoXvSink
|
||||
*
|
||||
*
|
||||
*
|
||||
GstBin
|
||||
GstPipeline
|
||||
GstThread
|
||||
GstConnection
|
||||
GstQueue
|
||||
GstNetwork
|
||||
GstSHM
|
||||
|
||||
|
||||
GstObject:
|
||||
|
||||
Base class for all streamer objects (duh), defines some basic stuff like a
|
||||
pointer to the master pipeline for the object.
|
||||
|
||||
|
||||
GstBin:
|
||||
|
||||
Contains a bunch of GstObjects.
|
||||
|
||||
|
||||
GstPipeline:
|
||||
|
||||
A bin that can be used raw in an application. The object that gets
|
||||
embedded into applications. Can contain any set of GstObjects. Nothing
|
||||
but a convenience object for the moment, will eventually be *the* object
|
||||
dealt with externally.
|
||||
|
||||
|
||||
GstThread:
|
||||
|
||||
A bin that will become a thread if possible when the pipeline is started
|
||||
up. Can contain any set of GstObjects except another GstThread. All
|
||||
starting points and/or clocked events must be registered with this object,
|
||||
to be dealt with in the separate thread.
|
15
docs/random/buffers
Normal file
15
docs/random/buffers
Normal file
|
@ -0,0 +1,15 @@
|
|||
Buffer mutability properties are the most important part of gst, and
|
||||
similarly are the most complex.
|
||||
|
||||
The simple case is that a buffer is created, memory allocated, data put
|
||||
in it, and passed to the next filter. That filter reads the data, does
|
||||
something (like creating a new buffer and decoding into it), and
|
||||
unreferences the buffer. This causes the data to be freed and the buffer
|
||||
to be destroyed.
|
||||
|
||||
A more complex case is when the filter modifies the data in place. It
|
||||
does so and simply passes on the buffer to the next element. This is just
|
||||
as easy to deal with.
|
||||
|
||||
If the second filter adds metadata to the buffer, it just has to add the
|
||||
pointer to the list. The next element simply traverses the list and
|
5
docs/random/coroutines
Normal file
5
docs/random/coroutines
Normal file
|
@ -0,0 +1,5 @@
|
|||
In a cothread-based container, all elements are run as cothreads.
|
||||
Chain-function based elements are wrapped by a generic element-class
|
||||
function that just calls the chain function repeatedly after pulling a
|
||||
buffer for it. (in reality, chain functions are only usable in the
|
||||
single-input case)
|
12
docs/random/design
Normal file
12
docs/random/design
Normal file
|
@ -0,0 +1,12 @@
|
|||
The fundamental component of GStreamer is the "element", an object that
|
||||
sources and/or sinks data. Elements are connected to each other via
|
||||
"pads", which are extremely light-weight generic connections. Elements
|
||||
can be contained inside "bins", which themselves are elements.
|
||||
|
||||
A pipeline consists of any number of elements, connected to each other one
|
||||
after another. A source would connect to one end of a decoder, which in
|
||||
turn would be connected (on the other end) to a sink, such as a sound
|
||||
card. Other elements can be located anywhere in the pipeline, including
|
||||
tees and transcoders.
|
||||
|
||||
|
104
docs/random/example
Normal file
104
docs/random/example
Normal file
|
@ -0,0 +1,104 @@
|
|||
Here's a pipeline that does audio/video MPEG streams with a queue on
|
||||
either side of each decompressor, for a total of 5 threads (read/split,
|
||||
decode audio, decode video, play audio, play video):
|
||||
|
||||
NOTES: mpegsplit is the intelligence in this pipeline, providing an IDL
|
||||
that allows one to connect things to a GUI.
|
||||
|
||||
Pipeline(mpegplay)
|
||||
Thread(reader)
|
||||
Element(:disk_async_src) [StreamerAsyncSrc]
|
||||
OutPad(disk1)
|
||||
Element(:mpegsplit)
|
||||
InPad(disk1)
|
||||
OutPad(audio1)
|
||||
OutPad(video1)
|
||||
|
||||
Queue(audioQ1)
|
||||
InPad(audio1)
|
||||
OutPad(audio2)
|
||||
Thread(audiodecode)
|
||||
Element(:mpeg_audio_decode) [StreamerVideoFilter]
|
||||
InPad(audio2)
|
||||
OutPad(audio3)
|
||||
Queue(audioQ2)
|
||||
InPad(audio3)
|
||||
OutPad(audio4)
|
||||
Thread(audioplay)
|
||||
Element(:audio_play) [StreamerAudioSink]
|
||||
InPad(audio4)
|
||||
|
||||
Queue(videoQ1)
|
||||
InPad(video1)
|
||||
OutPad(video2)
|
||||
Thread(videodecode)
|
||||
Element(:mpeg_video_decode) [StreamerVideoFilter]
|
||||
InPad(video2)
|
||||
OutPad(video3)
|
||||
Queue(videoQ2)
|
||||
InPad(video3)
|
||||
OutPad(video4)
|
||||
Thread(videoplay)
|
||||
Element(:video_play) [StreamerVideoSink]
|
||||
InPad(video4)
|
||||
|
||||
|
||||
A simpler pipeline that just does MPEG videos:
|
||||
|
||||
Pipeline(mpegplay)
|
||||
Thread(reader)
|
||||
Element(:disk_async_src) [GstAsyncSrc]
|
||||
OutPad(disk1)
|
||||
Element(:mpeg_control)
|
||||
InPad(disk1)
|
||||
OutPad(video1)
|
||||
Element(:mpeg_video_decode) [GstVideoFilter]
|
||||
InPad(video1)
|
||||
InPad(video2)
|
||||
Queue(queue)
|
||||
InPad(video2)
|
||||
OutPad(video3)
|
||||
Thread(play)
|
||||
Element(:video_play) [GstVideoSink]
|
||||
InPad(video3)
|
||||
|
||||
The code for the above looks roughly like:
|
||||
|
||||
/* all the objects we're worried about */
|
||||
GstPipeline *mpegplay;
|
||||
GstThread *reader;
|
||||
GstSrc *disk_src;
|
||||
GstControl *mpeg_control;
|
||||
GstFilter *mpeg_video_decode;
|
||||
GstQueue *queue;
|
||||
GstThread *play;
|
||||
GstSink *video_play;
|
||||
|
||||
/*** first we create all of the objects ***/
|
||||
|
||||
mpegplay = gst_pipeline_new();
|
||||
reader = gst_thread_new();
|
||||
disk_src = gst_async_disk_src_new("filename.mpg");
|
||||
mpeg_control = gst_mpeg_control_new();
|
||||
mpeg_video_decode = gst_mpeg_video_decode_new();
|
||||
queue = gst_queue_new();
|
||||
play = gst_thread_new();
|
||||
video_play = gst_video_sink_new();
|
||||
|
||||
|
||||
/*** now we start to create the pipeline ***/
|
||||
|
||||
/* first set up the reader thread */
|
||||
gst_bin_add(reader,disk_src);
|
||||
gst_object_connect(disk_src,"out",mpeg_control,"in");
|
||||
gst_object_connect(mpeg_control,"out",mpeg_audio_decode,"in");
|
||||
gst_bin_ghost_pad(reader,mpeg_audio_decode,"out");
|
||||
|
||||
/* then set up the player thread */
|
||||
gst_bin_add(play,audio_play);
|
||||
gst_bin_ghost_pad(play,audio_play,"in");
|
||||
|
||||
/* now plug them all into the main pipeline */
|
||||
gst_bin_add(mp3play,reader);
|
||||
gst_object_connect(reader,"out",queue,"in");
|
||||
gst_object_connect(queue,"out",play,"in");
|
7
docs/random/factoryinfo
Normal file
7
docs/random/factoryinfo
Normal file
|
@ -0,0 +1,7 @@
|
|||
short name
|
||||
class
|
||||
long name
|
||||
descripion
|
||||
author
|
||||
version
|
||||
copyright
|
4
docs/random/gboolean
Normal file
4
docs/random/gboolean
Normal file
|
@ -0,0 +1,4 @@
|
|||
NOTE TO SELF:
|
||||
|
||||
there are a lot of routines here that should be returning gboolean's for
|
||||
status, rather than just plain failing.
|
17
docs/random/intro
Normal file
17
docs/random/intro
Normal file
|
@ -0,0 +1,17 @@
|
|||
GNOME Streamer is a pipeline-based media streaming framework. It is built
|
||||
on top of the Gtk+ object model, and while it currently sits on top of
|
||||
gtk, it can be divorced from it at any point in the future.
|
||||
|
||||
A pipeline consists of at one or more each of sources, sinks, and filters.
|
||||
These elements may be combined inside container elements, which may have
|
||||
their own specific properties, and act as any other element. Each element
|
||||
has one or more pads, which are connection points. These pads are
|
||||
connected to chain from one element to the next, providing a path along
|
||||
which buffers are passed.
|
||||
|
||||
Operation of the pipeline is fully automatic once a buffer is put in the
|
||||
front of the pipeline. As each element finishes its processing, it pushes
|
||||
the buffer to the next element through an indirect function call, by way
|
||||
of the two connected pads.
|
||||
|
||||
|
77
docs/random/metadata
Normal file
77
docs/random/metadata
Normal file
|
@ -0,0 +1,77 @@
|
|||
The point of the metadata is to provide some context for each buffer. In
|
||||
the case of audio data, for instance, it would provide the samplerate, bit
|
||||
depth, and channel count.
|
||||
|
||||
The trick is that there may be multiple types of metadata ganged onto a
|
||||
single buffer. This is why they're going to be a GList. This does mean
|
||||
extra overhead in all cases, but I think it's minimal. The GList type
|
||||
uses a chunk allocater so we're not wasting too much memory or time when
|
||||
adding to the list.
|
||||
|
||||
The trick is dealing with these structs as they pass through a pipeline,
|
||||
since they have potentially different mutability properties. For
|
||||
instance, if you've got a mp3 decoder connected to a tee, which sends the
|
||||
buffers off to both the decoder and a spectrum analyzer (and then a
|
||||
visualization element). The preferred setup would be where every time a
|
||||
audio/raw metadata comes down the pipe (indicating a potential change in
|
||||
audio format), the audiosink and spectrum would just save off pointers.
|
||||
|
||||
So when exactly does this metadata go away (deallocated)? Well, that
|
||||
means metadata has to be refcounted. But that gets rather hairy. OK, in
|
||||
the simple case you create a metadata struct, it comes with refcount set
|
||||
to 1. You pass it through, it stays one, eventually someone drops the
|
||||
last reference on the buffer it's tied to, you free the metadata too.
|
||||
Easy. What if you tee? You could go through and for every metadata in
|
||||
the buffer, increment the refcount by the same as the buffer. So in the
|
||||
above case (tee'd), the audiosink and spectrum would get the buffer with a
|
||||
refcount of 2, and it'd have a metadata with refcount 2. Do they ref it
|
||||
each themselves, then unref the buffer? Or do they remove the metadata?
|
||||
Removing the metadata would require a buffer CoW, which would suck, so
|
||||
yes, they'd just ref the metadata.
|
||||
|
||||
But.... what if they're all in different threads? Then we're off into
|
||||
the magical world of mutexes. Everything with a refcount in a threaded
|
||||
world must be mutexed, else you can do atomic increment and atomic
|
||||
dec&test. Can this be done from C easily? Perhaps it needs to be found
|
||||
from kernel includes via autoconf?
|
||||
|
||||
|
||||
|
||||
|
||||
The goal in designing the way metadata will be defined and used is to keep
|
||||
it as simple as possible. The basis for accomplishing this is the fact
|
||||
that in order to actually use (rather than just pass) the metadata, you
|
||||
have to know what the fields are, which means you have to have compiled in
|
||||
support for that metadata at build time. Therefore, if you're using
|
||||
metadata, you must have build-time access to the necessary include file
|
||||
that defines it.
|
||||
|
||||
So, given that you've got an include file, it would be nice if the whole
|
||||
thing could be contained there. This would limit the need to be linked
|
||||
against something, or have load-time requirements as to that has to be
|
||||
loaded before you are.
|
||||
|
||||
Given that really all metadata is is a region of memory of a given size
|
||||
with a certain signature, this isn't all that hard. First you lay out the
|
||||
struct that defines the metadata. Then you set up #defines that expand to
|
||||
the size of the struct in question, as well as the four-cc code that
|
||||
defines the type.
|
||||
|
||||
The work is done by a few #defines, a la the #defines used in all Gtk
|
||||
objects. The first is a NEW() method that allocates the memory for the
|
||||
metadata and fills in all the normal fields (type, size, utility
|
||||
functions). Because of the way it's defined (as a #define, no less),
|
||||
you'll have to invoke it as META_NEW(meta), since it can't return()
|
||||
anything.
|
||||
|
||||
Another #define will check to make sure a meta is indeed that type by
|
||||
verifying the type code and size. Theoretically, meta types can overlap
|
||||
with the same fourcc code, as long as they have different sizes. But I
|
||||
probably ought to have a global public registry so people writing things
|
||||
don't conflict. MSFT got that right, at least.
|
||||
|
||||
So, a hairy problem is what to do when there are utility functions
|
||||
associated with one of these things. One option is to not bother with
|
||||
them. This is very likely a possible solution, since metadata is supposed
|
||||
to be flat memory of a given size. Not much to do to either free or copy
|
||||
it, is there?
|
30
docs/random/mutability
Normal file
30
docs/random/mutability
Normal file
|
@ -0,0 +1,30 @@
|
|||
Mutability is the property of an object that defines whether or not you
|
||||
are allowed to modify it. In the context of GST, that means that if you
|
||||
want to mutilate a buffer, say to do an audio effect, you may have to do
|
||||
this on a copy of the buffer, if someone else has a reference on it.
|
||||
|
||||
The simplest sequence of events in a decoder pipeline is as follows:
|
||||
|
||||
1) create buffer
|
||||
2) allocate and fill data region, attach to buffer
|
||||
3) pass to next element
|
||||
4) decode the data into new buffer, free original buffer
|
||||
5) pass to next element
|
||||
6) buffer gets copied to output device (sound, video, whatever)
|
||||
|
||||
Both of these buffers are created from malloc()'d memory, are referenced
|
||||
by one and only one element at a time, and are never modified in place.
|
||||
They have no special flags, and when ref==0, they're simply free()'d.
|
||||
|
||||
An optimization in the case of the sound card or video double buffering,
|
||||
where the output buffer actually comes from the output device. In that
|
||||
case the element will be aware of such things.
|
||||
|
||||
A more complex example is where the data is teed after being decoded, sent
|
||||
to an effects or visualization object.
|
||||
|
||||
1) create buffer, fill from source
|
||||
2) hand to decoder
|
||||
3) create new buffer, decode into it, free old buffer
|
||||
4) hand to tee
|
||||
5) ref++, hand off to
|
14
docs/random/padarch
Normal file
14
docs/random/padarch
Normal file
|
@ -0,0 +1,14 @@
|
|||
--src---------------------------- --sink----------------------------
|
||||
| |
|
||||
--srcpad--------| |--sinkpad-------
|
||||
| pad_push() . . |
|
||||
push() | ->chain . . ->chain | -> chain()
|
||||
| . . |
|
||||
----------------| |----------------
|
||||
| |
|
||||
|
||||
chain() is the function provided by sink element
|
||||
sinkpad->chain is a pointer to that function
|
||||
srcpad->chain should be a copy of that pointer
|
||||
pad_push() calls the function pointer srcpad->chain
|
||||
push() is the function provided by the src element
|
15
docs/random/sequence
Normal file
15
docs/random/sequence
Normal file
|
@ -0,0 +1,15 @@
|
|||
Here's a possible (huge, large, complete?) sequence of execution for an
|
||||
invocation of [GIST] playing a media stream. I'll start with a mp3 audio
|
||||
stream, but eventually this should be a mpeg a/v stream off the net with
|
||||
rolling capture (think ReplayTV/Tivo), pausing, rewinding, etc. This
|
||||
could easily be hundreds of lines by the time I'm done...
|
||||
|
||||
This may look a lot like C in places, simply because that's the most
|
||||
efficient way of representing a given action.
|
||||
|
||||
|
||||
gst_init();
|
||||
pipeline = gst_pipeline_new();
|
||||
state =
|
||||
src = gst_disksrc_new("src","song.mp3");
|
||||
|
45
docs/random/state-transitions
Normal file
45
docs/random/state-transitions
Normal file
|
@ -0,0 +1,45 @@
|
|||
So, the method of having a _start() and _stop() function for each element
|
||||
just doesn't scale. In the case of pipeline/thread model with a PLAYING
|
||||
state bit, I have no way of passing a state change all the way down the
|
||||
graph, i.e. a thread sitting inside a supplied bin.
|
||||
|
||||
Proposal is to have a single state-change class function, which gets
|
||||
passed a single argument (no more 'state' going along with RUNNING). This
|
||||
function can be overridden by each element as necessary, but must chain to
|
||||
the parent_class version of it. It does its work, just like [st]et_arg,
|
||||
in a case. It checks for STATE and ~STATE, and does the appropriate
|
||||
steps. All the _start() and _stop() functions get moved into this one, in
|
||||
the GST_STATE_RUNNING and ~GST_STATE_RUNNING cases.
|
||||
|
||||
This allows bins to and derivations thereof to simply pass through any
|
||||
state they don't understand. Meta-elements will also pass through.
|
||||
|
||||
There may need to be some mechanism that provides for setting state on
|
||||
only a certain type. This can be provided as an alternate path supplied
|
||||
by bins. The bin is the one that would do the work in any case. Simply
|
||||
provide class function for bins that does the selective stuff, and a main
|
||||
_bin_ function that calls this class function. The supplied class
|
||||
function for each bin would simply check against the given GtkType before
|
||||
setting its state. Derivations of GstBin would always get it.
|
||||
|
||||
Success chaining (gbooleans) starts to get a little hairier...
|
||||
|
||||
|
||||
Functions:
|
||||
|
||||
gst_element_set_state(element,state) is called by the application to set
|
||||
the state for an element (or bin).
|
||||
|
||||
elementclass->change_state() is the class function that actually does the
|
||||
setting of the state for this element. Any subclass implementation will
|
||||
chain to the parent_class's version.
|
||||
|
||||
gst_element_change_state(element,state) is the Element class's
|
||||
implementation of the change_state() function. It simply sets the state.
|
||||
|
||||
|
||||
gst_bin_set_state_type(element,state,type) is a specialized function for
|
||||
bins only that sets the type only on elements of that type.
|
||||
|
||||
binclass->change_state_type() is the class function that does the
|
||||
selective
|
71
docs/random/states
Normal file
71
docs/random/states
Normal file
|
@ -0,0 +1,71 @@
|
|||
GST State Bits and Transition Rules (graph to follow)
|
||||
-----------------------------------
|
||||
|
||||
These are the 'new' state bits and what they mean.
|
||||
|
||||
What the state bits are:
|
||||
GST_STATE_COMPLETE: if the element has enough data, but is not in any kind
|
||||
of running or explicitely stopped state. ready to be used.
|
||||
GST_STATE_RUNNING: this is the normal state of the pipeline, where data
|
||||
goes all the way through the pipeline normally.
|
||||
GST_STATE_DISCOVERY: anything the element does in this state must be reset
|
||||
after discovery. any data read from sync source must be cached.
|
||||
GST_STATE_PREROLL: not a lot different from PLAYING, except sinks don't
|
||||
render what they're getting. useful for elements that require
|
||||
data to get in sync, such as an MPEG video decoder that needs
|
||||
IBBPBB before starting at the next P.
|
||||
|
||||
|
||||
|
||||
Basic transition rules:
|
||||
|
||||
Completeness is based on the element having enough information to actually
|
||||
do something. GST_STATE_COMPLETE is required for any other state to be
|
||||
valid, though the only invariant is that you can't be RUNNING unless
|
||||
you're COMPLETE. In fact, AFAICT, that's the *only* invariant.
|
||||
|
||||
The element is entirely in control of this bit at all times. There is no
|
||||
way to externally change this bit except by changing the state of the
|
||||
element in such a way as to effect a change.
|
||||
|
||||
|= GST_STATE_COMPLETE
|
||||
setting whatever the last bit of info the element was looking for
|
||||
(gst_object_set)
|
||||
|
||||
&= ~GST_STATE_COMPLETE
|
||||
changing anything that invalidates the complete state of the element
|
||||
|
||||
|
||||
Whether the element is running or not, on the other hand, is almost
|
||||
entirely out of the hands of the individual element. This is generally
|
||||
turned on by way of gst_element_run() as called by the parent (ultimately
|
||||
by the Pipeline), which happens to optionally call a function private to
|
||||
the element to prepare it. As per docs/random/gboolean, very likely this
|
||||
function should return a TRUE/FALSE.
|
||||
|
||||
Generally, I think if there is no such function, the generic element code
|
||||
should go ahead and set the state, and trigger the state_changed signal,
|
||||
returning TRUE. If there is a function, call it. If it returns TRUE,
|
||||
fire off the signal (since the signal is actually an Element signal
|
||||
anyway, why eat another function call?). Return the result regardless.
|
||||
|
||||
|= GST_STATE_RUNNING
|
||||
starting up the pipeline with gst_pipeline_start
|
||||
|
||||
~= ~GST_STATE_RUNNING
|
||||
stopping the pipeline with gst_pipeline_stop, or some error state
|
||||
|
||||
gst_pipeline_start() simply calls the gst_element_start() function on each
|
||||
of the elements in it. This sets the RUNNING bit of each element, and for
|
||||
GstBin's it loops through that list. gst_pipeline_start() is just a
|
||||
special case version of gst_bin_start(). All start() functions are
|
||||
GstElementClass functions, meaning you can start any element the same way.
|
||||
|
||||
The pipeline can be stopped the same way, but more likely the pipeline
|
||||
will be stopped due to some stoppage condition, such as EOF on the source
|
||||
file, or the parser being told to stop the stream. In the EOF case, it
|
||||
would turn its RUNNING bit off, then call the stop() class function on its
|
||||
parent. This would trigger an up-hill, breath-first traversal of the
|
||||
whole graph. Alternately, if each element lists its uber-parent (the
|
||||
Pipeline) it can simply inform the pipeline directly, causing a
|
||||
depth-first traversal just like the start() case.
|
80
docs/random/states.old
Normal file
80
docs/random/states.old
Normal file
|
@ -0,0 +1,80 @@
|
|||
GST States and Transition Rules (graph to follow)
|
||||
-------------------------------
|
||||
|
||||
This should be a map of possible state transitions and what triggers them.
|
||||
|
||||
What the states are:
|
||||
GST_STATE_NEW: a new element has this, if it has nothing set except name.
|
||||
GST_STATE_INCOMPLETE: any element that has some, but not enough
|
||||
information to function is in this state.
|
||||
GST_STATE_COMPLETE: if the element has enough data, but is not in any kind
|
||||
of running or explicitely stopped state. ready to be used.
|
||||
GST_STATE_DISCOVERY: anything the element does in this state must be reset
|
||||
after discovery. any data read from sync source must be cached.
|
||||
GST_STATE_PREROLL: not a lot different from PLAYING, except sinks don't
|
||||
render what they're getting. useful for elements that require
|
||||
data to get in sync, such as an MPEG video decoder that needs
|
||||
IBBPBB before starting at the next P.
|
||||
GST_STATE_RUNNING: this is the normal state of the pipeline, where data
|
||||
goes all the way through the pipeline normally.
|
||||
GST_STATE_STOPPED: an explicit stop state, different from COMPLETE in that
|
||||
the state doesn't get reset.
|
||||
|
||||
|
||||
NULL -> GST_STATE_NEW
|
||||
creating an element (gst_*_new*)
|
||||
|
||||
GST_STATE_NEW -> GST_STATE_INCOMPLETE
|
||||
setting anything in the element that isn't sufficient to bring it
|
||||
to a useful state (gst_object_set)
|
||||
|
||||
GST_STATE_INCOMPLETE -> GST_STATE_COMPLETE
|
||||
setting whatever the last bit of info the element was looking for
|
||||
(gst_object_set)
|
||||
|
||||
GST_STATE_COMPLETE -> GST_STATE_INCOMPLETE
|
||||
changing anything that invalidates the complete state of the element
|
||||
|
||||
GST_STATE_COMPLETE -> GST_STATE_DISCOVERY
|
||||
setting the state to DISCOVERY
|
||||
[ used for autoplug ]
|
||||
|
||||
GST_STATE_DISCOVERY -> GST_STATE_COMPLETE
|
||||
setting the state !DISCOVERY
|
||||
[ used when autoplug is over ]
|
||||
|
||||
GST_STATE_DISCOVERY -> GST_STATE_PREROLL
|
||||
setting the state to PREROLL
|
||||
[ you can go straight to preroll from discovery if you want ]
|
||||
|
||||
GST_STATE_DISCOVERY -> GST_STATE_RUNNING
|
||||
setting the state to RUNNING
|
||||
[ you can even go straight to running from preroll ]
|
||||
|
||||
GST_STATE_DISCOVERY -> GST_STATE_STOPPED
|
||||
setting the state to STOPPED
|
||||
[ normally you'd go from discovery to stopped when you load a src ]
|
||||
|
||||
GST_STATE_PREROLL -> GST_STATE_RUNNING
|
||||
setting the state to RUNNING
|
||||
[ preroll generally leads straight to running, as in above ]
|
||||
|
||||
GST_STATE_PREROLL -> GST_STATE_STOPPED
|
||||
setting the state to STOPPED
|
||||
[ it is possible to go to stopped, i.e load file@time ]
|
||||
|
||||
GST_STATE_RUNNING -> GST_STATE_PREROLL
|
||||
setting the state to PREROLL
|
||||
[ unsure if you'd need this state, you'd go to stopped first ]
|
||||
|
||||
GST_STATE_RUNNING -> GST_STATE_STOPPED
|
||||
setting the state to STOPPED
|
||||
[ pause. ]
|
||||
|
||||
GST_STATE_STOPPED -> GST_STATE_PREROLL
|
||||
setting the state to PREROLL
|
||||
[ if you seek to intermediate time while stopped, you'd preroll to
|
||||
prepare to start running again immediately ]
|
||||
|
||||
GST_STATE_STOPPED -> GST_STATE_RUNNING
|
||||
setting the state to RUNNING
|
33
docs/random/types
Normal file
33
docs/random/types
Normal file
|
@ -0,0 +1,33 @@
|
|||
GstTypes exist to try to make sure data eveyrone is talking about the
|
||||
right kind of data. They aid quite a bit in autoplugging, in fact make it
|
||||
possible. Each well-formed type includes a function (typefind) that will
|
||||
take one or more buffers and determine whether or not it is indeed a
|
||||
stream of that type, and possible a metadata to go with it. It may
|
||||
provide related metadata structure IDs (and must if it provides metadata
|
||||
from the typefind function).
|
||||
|
||||
Because multiple elements and plugins are very likely to be using the same
|
||||
types, the process of creating/finding types is designed to be done with a
|
||||
single function call. All operations on GstTypes occur via their guint16
|
||||
ID numbers, with the GstType structure "private" to the GST library. A
|
||||
plugin wishing to use a give type would contain a static struct of type
|
||||
GstTypeFactory, which lists the MIME type, possible extensions (which may
|
||||
overlap the mime-types file), a typefind function, and any other cruft I
|
||||
decide to add.
|
||||
|
||||
A plugin init function would take this typefactory and hand it to the
|
||||
gst_type_new() (FIXME: badly named) function, which would first search for
|
||||
that same MIME type in the current list. If it found one, it would
|
||||
compare the two to see if the new one is "better". Better is defined as
|
||||
having more extentions (to be merged) or a typefind function verses none.
|
||||
|
||||
The point of returning an existing MIME type is a result of the goal of
|
||||
unifying types enough to guarantee that, for instance, all MP3 decoders
|
||||
will work interchangably. If MP3 decoder A says "MIME type 'audio/mpeg'
|
||||
with extensions 'mpeg3'" and decoder B says "MIME type 'audio/mpeg' with
|
||||
extensions 'mp3'", we don't want to have two types defined, possibly with
|
||||
two typefind functions. If we did, it's not obvious which of the two would
|
||||
be tried first (luck) and if both would really identify streams as mp3
|
||||
correctly in all cases. And whichever wins, we're stuck using the
|
||||
associated decoder to play that stream. We lose the choice between any
|
||||
valid mp3 decoder, and thus the whole point of the type system.
|
78
docs/random/vis-transform
Normal file
78
docs/random/vis-transform
Normal file
|
@ -0,0 +1,78 @@
|
|||
Duh, an 'easy' way to replicate Giess's behavior:
|
||||
|
||||
For each frame, you have to mutate it by a transform matrix. This is
|
||||
easy, thought not cheap. First you precalculate the transform matrix how
|
||||
you want it, based on whatever rotations or whatever you want.
|
||||
|
||||
The data stored in each spot on the matrix tells you how to transform a
|
||||
single pixel. The simple case is dx,dy, where both are relatively small.
|
||||
The probably ought to be a byte in any case, so you can scale the
|
||||
transform matrix on slow machines. A more complex case is some trick
|
||||
whereby a single pixel ends up splattered in several places. Idea below.
|
||||
|
||||
The matrix consists of some number of 8bit arrays of the same size as the
|
||||
image. They'd probably be line-interleaved or better to help with cache
|
||||
effects (which are VERY serious here). Each channel represents some
|
||||
aspect of the transform. The first two would likely be dx and dy, the
|
||||
third might be a multiplier if that wasn't done statically.
|
||||
|
||||
The idea: any number of transform sets could be applied, given available
|
||||
processing power. Just set the static scalar or the multiplier matrices
|
||||
so you don't completely swamp the output pixels.
|
||||
|
||||
Note that this is fastest in 8-bit, but theoretically could be applied to
|
||||
32 bit. 15 and 16 are hard, since you can't easily apply the multipliers
|
||||
unless they're 1/2^n, and even then it's significantly heavier (you'd have
|
||||
to mask the top n bits of each color out).
|
||||
|
||||
This SCREAMS for MMX, in case you haven't figured it out yet.
|
||||
Unfortunatley, MMX is only directly useful for the scalar matrix, unless
|
||||
you do a trick where all the pixels in that fit in 64 bits (8 8bit, 4
|
||||
16bit, or 2 32bit) are always moved in a group. This is very possible,
|
||||
and might be a significant perf increase by being able to use MMX all the
|
||||
way through. Otherwise you have to place each pixel by extracting the MMX
|
||||
stuff back into normal registers, and that just plain sucks.
|
||||
|
||||
A pseudo-C implementation:
|
||||
|
||||
----- BEGIN -----
|
||||
gint x,y; /* image x and y size */
|
||||
guchar old_image[x][y]; /* original image */
|
||||
guchar new_image[x][y]; /* new image */
|
||||
gchar x_xform[x][y]; /* dx matrix */
|
||||
gchar y_xform[x][y]; /* dy matrix */
|
||||
guchar s_xform[x][y]; /* intensity scalar matrix */
|
||||
guchar scalar; /* global scalar */
|
||||
|
||||
gint i,j; /* indixes */
|
||||
gulong p; /* pixel value in question */
|
||||
guchar u,v,w; /* modifier variables */
|
||||
|
||||
/* clear the new image, we don't want anything getting in the way */
|
||||
/* NOT NECESSARILY A GOOD THING, THOUGH */
|
||||
memset(new_image,0,x*y);
|
||||
|
||||
/* loop through all the lines in the image */
|
||||
for (j=0;j<y;j++) {
|
||||
/* loop through all the pixels in the line */
|
||||
for (i=0;i<x;i++) {
|
||||
p = old_image[i][j];
|
||||
u = x_xform[i][j];
|
||||
v = y_xform[i][j];
|
||||
w = s_xform[i][j];
|
||||
new_image[i+u][j+v] = (guchar)((p<<14) / (w * scalar));
|
||||
}
|
||||
}
|
||||
----- END -----
|
||||
|
||||
Note that the above really, *REALLY* sucks performance-wise. Throw it a
|
||||
80x60 image and it'll swamp my poor laptop. Also note that I simply set
|
||||
the pixel value, not merge it. That means you'd better be sure your
|
||||
transform matrix doesn't have overlapping destinations.
|
||||
|
||||
Other notes about the above code: x_xform and y_xform are signed chars,
|
||||
which means pixels can move in all directions. The intensity matrix is
|
||||
unsigned, with a range from 0 to 255, so is the global scalar. Note the
|
||||
shift of 14bits (2 * 7bits), then divide by each. That means identity for
|
||||
both scalars is at 128. The FP range of each is thus 0.0 to 2.0. Very
|
||||
handy.
|
39
docs/random/walkthrough
Normal file
39
docs/random/walkthrough
Normal file
|
@ -0,0 +1,39 @@
|
|||
You might start by creating a source element and put it into a pipeline.
|
||||
At this point both element's state would be GST_STATE_NEW, since they
|
||||
don't have enough state to actually run yet. At this point you can set
|
||||
the filename of the source, and possibly bytesperread and other things.
|
||||
|
||||
Then you'd want to discover the data type of the file you're sourcing.
|
||||
This will typically be handled by the pipeline itself by calling
|
||||
gst_pipeline_autoplug(), or gst_pipeline_find_pad_type(), or somesuch. The
|
||||
pipeline would first set its state to GST_STATE_DISCOVERY. A gstfindtype
|
||||
sink would be added to the pipeline and connected to the source. Its
|
||||
HAVE_TYPE signal would be connected to a private pipeline function.
|
||||
|
||||
The pipeline would then set the the src state to GST_STATE_DISCOVERY, and
|
||||
call the src's push() function until a the type is set by the function
|
||||
connected to the gstfindtype element's signal. At this point the pipeline
|
||||
would disconnect the gstfindtype element from the src, set the type of the
|
||||
pad to the type returned by the gstfindtype element. At disconnection of
|
||||
the find element, the src's state automatically reverts to NEW.
|
||||
|
||||
(The trick with the sources when they do DISCOVERY is that synchronous
|
||||
sources can't go back and read data again. So perhaps I should set up a
|
||||
wrapper function for the push() function that uses either a sync or
|
||||
async function as provided by the src instance to provide DISCOVERY and
|
||||
normal operations. It would use a [GstBufferCache] to read ahead into
|
||||
memory if necessary, creating baby buffers as necessary to answer the
|
||||
needs of each DISCOVERY sequence.)
|
||||
|
||||
If you called find_pad_type(), it would return right about now, with the
|
||||
ID of the type it found. At the same time, if you have connected a signal
|
||||
to the pad's SET_TYPE signal, it would fire right as the type is set by
|
||||
the find_pad_type() function. This would allow your application to do its
|
||||
own selection of filters to connect to the pad.
|
||||
|
||||
If you called autoplug(), the pipeline would make a selection of element
|
||||
to connect. The element would be created (state=NEW), added to the
|
||||
pipeline, and the appropriate sink pad connected to the src in question.
|
||||
(Note that multi-sink elements won't be supported unless there's a really
|
||||
good and obvious way to do so) The whole process would repeat until the
|
||||
recently added element no longer has a src pad.
|
4
docs/slides/README
Normal file
4
docs/slides/README
Normal file
|
@ -0,0 +1,4 @@
|
|||
These are notes for slides to be presented at the OGI DISC Cookie Talk,
|
||||
Oct 22, 1999. Outline will be text, probably written up in PowerPoint for
|
||||
ease of presentation, and converted to .ps, .pdf, and .html once the talk
|
||||
has been given.
|
9
docs/slides/abstract
Normal file
9
docs/slides/abstract
Normal file
|
@ -0,0 +1,9 @@
|
|||
Intro to GStreamer
|
||||
|
||||
GStreamer is a media-streaming architecture that I've been developing at
|
||||
home for about 4 months now. It's designed to overcome some of the
|
||||
problems I've seen in both the OGI Pipeline and in reading through
|
||||
DirectShow docs. After an overview of the existing OGI Pipeline, I'll
|
||||
cover GStreamer's existing and planned architecture, and list what remains
|
||||
to be done. GStreamer is mostly frozen right now, as it is to be released
|
||||
as 0.1.0 on Oct 31. Major thaw will occur in a few weeks.
|
10
docs/slides/abstract.save
Normal file
10
docs/slides/abstract.save
Normal file
|
@ -0,0 +1,10 @@
|
|||
Intro to GStreamer
|
||||
|
||||
GStreamer is a media-streaming architecture that I've been developing at
|
||||
home for about 4 months now. It's designed to overcome some of the
|
||||
problems I've seen in both the OGI Pipeline and in reading through
|
||||
DirectShow docs. After an overview of the existing OGI Pipeline, I'll
|
||||
cover GStreamer's existing and planned architecture, and list what remains
|
||||
to be done. GStreamer is mostly frozen right now, as it is to be released
|
||||
as 0.1.0 on Oct 31. Major thaw will occur in a few weeks.
|
||||
|
144
docs/slides/outline
Normal file
144
docs/slides/outline
Normal file
|
@ -0,0 +1,144 @@
|
|||
Introduction (1)
|
||||
(sorry, no cool logo/graphic yet, ideas?)
|
||||
GStreamer is a library and set of tools to build arbitrary,
|
||||
reconfigurable filter graphs. It derives from the OGI Pipeline
|
||||
and DirectShow (docs, no experience), and is in its second
|
||||
generation (first was completed/abandonded *in* Atlanta on the
|
||||
way to the Linux Expo).
|
||||
0.1.0 release is scheduled for Oct 31, 1999.
|
||||
Will cover Background, Goals, Design, and Futures
|
||||
Why do we need this?
|
||||
launch reads the command line to create the graph, from .so's
|
||||
Connections (queues) are made by launcher, lots of switchout code
|
||||
Argument handling is messy, at start-time only
|
||||
...thus there is basically only one state: running
|
||||
There is no real master process capable of seeing the whole
|
||||
pipeline as a graph, so wiring A->B->C with some backchannel
|
||||
(parameter, not data stream) from C to A is hard
|
||||
Channels try to do IPC, file, and network I/O, excess abstraction
|
||||
Goals (1)
|
||||
Provide a clean way to both build graphs and write new elements
|
||||
Make things easier by providing auto-connect, stock sub-graphs
|
||||
Include tools sorely lacking in OGI pipeline, like editor, saves
|
||||
Enable Linux to catch up with M$'s world, allowing commercial
|
||||
plugins to a stable API (as of 1.0) so we don't end up with N
|
||||
wheels from N-M different people (multiple projects)
|
||||
Overview (1)
|
||||
Object hierarchy capable of run-time discovery, based on GtkObject
|
||||
Deeply nested parent-child relationships enable threads, blackboxes
|
||||
Buffers can point to anything, are typed, and can carry metadata
|
||||
Plugins can be loaded at any point, and registry reduces loads
|
||||
Symbiotic editor lets you design/run/save graphs visually
|
||||
What are filter graphs? (1)
|
||||
Filters take data in and spit data out, doing something to it
|
||||
Filters have N>=0 inputs and M>=0 outputs
|
||||
Filter graphs are many filters connected together, like a circuit
|
||||
The goal is typically to move data from 'left' to 'right', towards
|
||||
some kind of user-visible conclusion, i.e. audio or video
|
||||
Architecture (3?)
|
||||
- Graphs of Elements
|
||||
(here lies screen-grab from editor)
|
||||
Element is core Object, Bins hold (and are) Elements
|
||||
Pads are fundamental to an Element, are cross-wired with pointers
|
||||
Since Bins hold Elements, and Bins are Elements, Bins hold Bins
|
||||
'Ghostpads' provide interfaces for Bins without native interfaces
|
||||
# Threads are type of Bin that actually run in separate threads
|
||||
|
||||
- States
|
||||
(table of states, invariants, and descriptions)
|
||||
COMPLETE Element has all needed information
|
||||
RUNNING Element has acquired resources, ready to go
|
||||
DISCOVERY ... (unimplemented)
|
||||
PREROLL ... (unimplemented)
|
||||
PLAYING Element is actively trading data
|
||||
PAUSED Special state where things just don't run (?..)
|
||||
States are used to keep elements in check
|
||||
|
||||
- Buffers
|
||||
Buffers designed to be versatile, with arbitrary typing/metadata
|
||||
Has pointer to data, length, so can point to someone else's data
|
||||
Type system (crude so far) ensures buffers don't go stray
|
||||
Metadata can be attached, such as the audio parameters
|
||||
Ref-counting and copy-on-write avoids most copies, not complete
|
||||
Sub-buffers can be created from bigger buffer, limitting copies
|
||||
Gtk+ Object System (2)
|
||||
- Pros
|
||||
C-language object system, well tested (Gtk+, Gnome...)
|
||||
Arguments of any fundamental type, read/write, built-in hooks
|
||||
Signals used for hooks into object events, overridable
|
||||
Run-time discovery of args, signals (quarks)
|
||||
- Cons
|
||||
No multiple-inheritance, though I haven't *needed* it
|
||||
There are some holes (can't attach quarks to *eveything*)
|
||||
|
||||
- Design
|
||||
Classes, instances are structs; 1st item is parent class
|
||||
Type system allows clean casting, ^^^^^^
|
||||
Arguments are set/get by string, use functions to do the work,
|
||||
thus setting an arg might trigger a redraw of the GUI
|
||||
Signals are strings, use marshallers, various firing methods
|
||||
Basic GStreamer objects (1)
|
||||
- Elements
|
||||
(show class,instance structs)
|
||||
Very simple, just provides a means to handle pads, state
|
||||
- Bins
|
||||
(show class,instance structs)
|
||||
Supports children, handles group state transitions
|
||||
Pads (1)
|
||||
Pad list type, direction, and chaining function ptr
|
||||
When creating a sink pad (!src) you set the chaining function
|
||||
gst_pad_connect() sets the peers, and copies chain function to src
|
||||
Passing buffer to a src pad transparently calls the chain function
|
||||
(graph goes here...)
|
||||
Sources (1)
|
||||
Source provides functions to push data
|
||||
Regular push() function just takes next N bytes and sends them
|
||||
Async push_region() grabs N bytes at offset O and sends them
|
||||
EOF signal [will] reset the state from PLAYING down to !RUNNING
|
||||
"location" argument is global by convention, for filenames...URIs
|
||||
Connections (1)
|
||||
Special type of Filter that
|
||||
Threads (1)
|
||||
Special case of Bin that actually creates a thread transparently
|
||||
When RUNNING, thread exists, mutex/cond used to go [!]PLAYING
|
||||
Automatically determines how to start sub-graph
|
||||
Looks for both Sources and Elements wired to Connection
|
||||
Will cooperate with Pipelines when threading is not available
|
||||
Typing and Metadata (1)
|
||||
- Types
|
||||
Based on MIME types, set up as quarks, and dealt with as int
|
||||
Usable entirely at run-time, since they're registerable by plugins
|
||||
- Metadata
|
||||
Also registered as an int, but must be compile time due to structs
|
||||
Have refcounts and CoW semantics, since they travel with buffers
|
||||
Plugins (1)
|
||||
Plugin architecture designed around class system
|
||||
Arguments and signals provide interface over standard base class
|
||||
Each Element defined by ElementFactory, which is queried by name
|
||||
At plugin load, any number of ElementFactories and Types registered
|
||||
Element registers against Type as source or sink
|
||||
Editor (2+?)
|
||||
(show filter graph snapshot, a different one, more complex)
|
||||
Built as a parallel object hierarchy on top of GNOME Canvas
|
||||
Every object in filter graph has equivalent in editor, plus some
|
||||
Canvas is designed with groups and signal-propagation, so...
|
||||
Why not build the whole thing as subclasses of CanvasGroup?
|
||||
|
||||
...because updates get messy/recursive (the way I *was* doing it)
|
||||
Solution is to modify objects so they own Group rather than being
|
||||
Relatively trivial modification, but requires lots of repointering
|
||||
Still a genealogical mess of parents and children...
|
||||
XML
|
||||
The goal is to use XML heavily, with an eye towards DOM
|
||||
Used for both saving and providing pre-build components
|
||||
Both graph and editor will have namespace, they'll interleave
|
||||
A generic save function will exist for Elements, with hooks
|
||||
Saving an EditorElement will also save Element
|
||||
Also used for a plugin registry, to avoid loading all plugins
|
||||
|
||||
|
||||
|
||||
|
||||
leaky bucket is trivial
|
||||
applications - generic conferencing tool (repluggable codecs), mixing
|
||||
environment (data flow graphs)
|
17
docs/slides/slides
Normal file
17
docs/slides/slides
Normal file
|
@ -0,0 +1,17 @@
|
|||
Introduction
|
||||
Why do we need this?
|
||||
Goals
|
||||
Overview
|
||||
What are filter graphs?
|
||||
Gtk+ Object System
|
||||
Architecture - Elements
|
||||
Pads
|
||||
Architecture - Buffers
|
||||
Typing and Metadata
|
||||
Sources
|
||||
Threads and Connections
|
||||
Architecture - States
|
||||
Plugins
|
||||
Editor
|
||||
XML
|
||||
Futures
|
32
editor/Makefile.am
Normal file
32
editor/Makefile.am
Normal file
|
@ -0,0 +1,32 @@
|
|||
LDFLAGS = $(GLIB_LIBS) $(GTK_LIBS) $(top_srcdir)/gst/libgst.la \
|
||||
$(shell gnome-config --libs gnomeui)
|
||||
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) -I$(top_srcdir)/gst \
|
||||
$(shell gnome-config --cflags gnomeui)
|
||||
|
||||
|
||||
lib_LTLIBRARIES = libgsteditor.la
|
||||
|
||||
libgsteditor_la_SOURCES = \
|
||||
gsteditor.c \
|
||||
gsteditorelement.c \
|
||||
gsteditorbin.c \
|
||||
gsteditorcanvas.c \
|
||||
gsteditorpad.c \
|
||||
gsteditorconnection.c \
|
||||
gstelementselect.c \
|
||||
gsteditorcreate.c
|
||||
|
||||
libgsteditorincludedir = $(includedir)/gst
|
||||
libgsteditorinclude_HEADERS = \
|
||||
gsteditor.h
|
||||
|
||||
|
||||
bin_PROGRAMS = editor
|
||||
editor_LDFLAGS = libgsteditor.la
|
||||
|
||||
|
||||
noinst_HEADERS = \
|
||||
gstelementselect.h \
|
||||
gsteditorcreate.h
|
||||
|
||||
EXTRA_DIST = editor.glade editorelement.glade
|
49
editor/editor.c
Normal file
49
editor/editor.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gnome.h>
|
||||
#include <libgnomeui/gnome-canvas.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gsteditor.h"
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GtkWidget *appwindow;
|
||||
GstEditor *editor;
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
gnome_init("GST Graph Editor",VERSION,argc,argv);
|
||||
|
||||
appwindow = gnome_app_new("gst-editor","GST Graph Editor");
|
||||
editor = gst_editor_new("pipeline");
|
||||
gtk_widget_set_usize(GTK_WIDGET(editor),250,250);
|
||||
gnome_app_set_contents(GNOME_APP(appwindow),GTK_WIDGET(editor));
|
||||
gtk_widget_show_all(appwindow);
|
||||
|
||||
gtk_main();
|
||||
|
||||
return(0);
|
||||
}
|
74
editor/editor.glade
Normal file
74
editor/editor.glade
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0"?>
|
||||
<GTK-Interface>
|
||||
|
||||
<project>
|
||||
<name>project1</name>
|
||||
<directory></directory>
|
||||
<source_directory></source_directory>
|
||||
<pixmaps_directory>pixmaps</pixmaps_directory>
|
||||
<language>C</language>
|
||||
<gnome_support>True</gnome_support>
|
||||
<gettext_support>True</gettext_support>
|
||||
<use_widget_names>False</use_widget_names>
|
||||
<main_source_file>gladesrc.c</main_source_file>
|
||||
<main_header_file>gladesrc.h</main_header_file>
|
||||
<handler_source_file>gladesig.c</handler_source_file>
|
||||
<handler_header_file>gladesig.h</handler_header_file>
|
||||
</project>
|
||||
|
||||
<widget>
|
||||
<class>GtkWindow</class>
|
||||
<name>editor_window</name>
|
||||
<title>GST Editor</title>
|
||||
<type>GTK_WINDOW_TOPLEVEL</type>
|
||||
<position>GTK_WIN_POS_NONE</position>
|
||||
<allow_shrink>False</allow_shrink>
|
||||
<allow_grow>True</allow_grow>
|
||||
<auto_shrink>False</auto_shrink>
|
||||
|
||||
<widget>
|
||||
<class>GtkVBox</class>
|
||||
<name>vbox3</name>
|
||||
<homogeneous>False</homogeneous>
|
||||
<spacing>0</spacing>
|
||||
|
||||
<widget>
|
||||
<class>Custom</class>
|
||||
<name>canvas_custom</name>
|
||||
<child>
|
||||
<padding>0</padding>
|
||||
<expand>True</expand>
|
||||
<fill>True</fill>
|
||||
</child>
|
||||
<creation_function>create_canvas</creation_function>
|
||||
<int1>0</int1>
|
||||
<int2>0</int2>
|
||||
</widget>
|
||||
|
||||
<widget>
|
||||
<class>GtkHBox</class>
|
||||
<name>hbox3</name>
|
||||
<child>
|
||||
<padding>0</padding>
|
||||
<expand>True</expand>
|
||||
<fill>True</fill>
|
||||
</child>
|
||||
<homogeneous>False</homogeneous>
|
||||
<spacing>0</spacing>
|
||||
|
||||
<widget>
|
||||
<class>GtkButton</class>
|
||||
<name>create_button</name>
|
||||
<child>
|
||||
<padding>0</padding>
|
||||
<expand>False</expand>
|
||||
<fill>False</fill>
|
||||
</child>
|
||||
<can_focus>True</can_focus>
|
||||
<label>Add Element</label>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
|
||||
</GTK-Interface>
|
143
editor/editorelement.glade
Normal file
143
editor/editorelement.glade
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?xml version="1.0"?>
|
||||
<GTK-Interface>
|
||||
|
||||
<project>
|
||||
<name>project1</name>
|
||||
<directory></directory>
|
||||
<source_directory></source_directory>
|
||||
<pixmaps_directory>pixmaps</pixmaps_directory>
|
||||
<language>C</language>
|
||||
<gnome_support>True</gnome_support>
|
||||
<gettext_support>True</gettext_support>
|
||||
<use_widget_names>False</use_widget_names>
|
||||
<main_source_file>gladesrc.c</main_source_file>
|
||||
<main_header_file>gladesrc.h</main_header_file>
|
||||
<handler_source_file>gladesig.c</handler_source_file>
|
||||
<handler_header_file>gladesig.h</handler_header_file>
|
||||
</project>
|
||||
|
||||
<widget>
|
||||
<class>GtkWindow</class>
|
||||
<name>window1</name>
|
||||
<title>window1</title>
|
||||
<type>GTK_WINDOW_TOPLEVEL</type>
|
||||
<position>GTK_WIN_POS_NONE</position>
|
||||
<allow_shrink>False</allow_shrink>
|
||||
<allow_grow>True</allow_grow>
|
||||
<auto_shrink>False</auto_shrink>
|
||||
|
||||
<widget>
|
||||
<class>GtkFrame</class>
|
||||
<name>element</name>
|
||||
<border_width>25</border_width>
|
||||
<label>mpegparse</label>
|
||||
<label_xalign>0</label_xalign>
|
||||
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
|
||||
|
||||
<widget>
|
||||
<class>GtkHBox</class>
|
||||
<name>hbox1</name>
|
||||
<homogeneous>False</homogeneous>
|
||||
<spacing>0</spacing>
|
||||
|
||||
<widget>
|
||||
<class>GtkVBox</class>
|
||||
<name>vbox1</name>
|
||||
<child>
|
||||
<padding>0</padding>
|
||||
<expand>True</expand>
|
||||
<fill>True</fill>
|
||||
</child>
|
||||
<homogeneous>False</homogeneous>
|
||||
<spacing>0</spacing>
|
||||
|
||||
<widget>
|
||||
<class>GtkFrame</class>
|
||||
<name>frame5</name>
|
||||
<child>
|
||||
<padding>0</padding>
|
||||
<expand>False</expand>
|
||||
<fill>False</fill>
|
||||
</child>
|
||||
<label_xalign>0</label_xalign>
|
||||
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
|
||||
|
||||
<widget>
|
||||
<class>GtkLabel</class>
|
||||
<name>src</name>
|
||||
<label>src</label>
|
||||
<justify>GTK_JUSTIFY_CENTER</justify>
|
||||
<xalign>0.5</xalign>
|
||||
<yalign>0.5</yalign>
|
||||
<xpad>0</xpad>
|
||||
<ypad>0</ypad>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
|
||||
<widget>
|
||||
<class>Placeholder</class>
|
||||
</widget>
|
||||
|
||||
<widget>
|
||||
<class>GtkVBox</class>
|
||||
<name>vbox3</name>
|
||||
<child>
|
||||
<padding>0</padding>
|
||||
<expand>True</expand>
|
||||
<fill>True</fill>
|
||||
</child>
|
||||
<homogeneous>False</homogeneous>
|
||||
<spacing>0</spacing>
|
||||
|
||||
<widget>
|
||||
<class>GtkFrame</class>
|
||||
<name>frame3</name>
|
||||
<child>
|
||||
<padding>0</padding>
|
||||
<expand>False</expand>
|
||||
<fill>False</fill>
|
||||
</child>
|
||||
<label_xalign>0</label_xalign>
|
||||
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
|
||||
|
||||
<widget>
|
||||
<class>GtkLabel</class>
|
||||
<name>audiosrc</name>
|
||||
<label>audiosrc</label>
|
||||
<justify>GTK_JUSTIFY_CENTER</justify>
|
||||
<xalign>0.5</xalign>
|
||||
<yalign>0.5</yalign>
|
||||
<xpad>0</xpad>
|
||||
<ypad>0</ypad>
|
||||
</widget>
|
||||
</widget>
|
||||
|
||||
<widget>
|
||||
<class>GtkFrame</class>
|
||||
<name>frame4</name>
|
||||
<child>
|
||||
<padding>0</padding>
|
||||
<expand>True</expand>
|
||||
<fill>True</fill>
|
||||
</child>
|
||||
<label_xalign>0</label_xalign>
|
||||
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
|
||||
|
||||
<widget>
|
||||
<class>GtkLabel</class>
|
||||
<name>videosrc</name>
|
||||
<label></label>
|
||||
<justify>GTK_JUSTIFY_CENTER</justify>
|
||||
<xalign>0.5</xalign>
|
||||
<yalign>0.5</yalign>
|
||||
<xpad>0</xpad>
|
||||
<ypad>0</ypad>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
|
||||
</GTK-Interface>
|
144
editor/gsteditor.c
Normal file
144
editor/gsteditor.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gnome.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gsteditor.h"
|
||||
|
||||
/* signals and args */
|
||||
enum {
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_NAME,
|
||||
};
|
||||
|
||||
static void gst_editor_class_init(GstEditorClass *klass);
|
||||
static void gst_editor_init(GstEditor *editor);
|
||||
|
||||
static void gst_editor_set_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_get_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
|
||||
static GtkFrame *parent_class = NULL;
|
||||
|
||||
GtkType gst_editor_get_type(void) {
|
||||
static GtkType editor_type = 0;
|
||||
|
||||
if (!editor_type) {
|
||||
static const GtkTypeInfo editor_info = {
|
||||
"GstEditor",
|
||||
sizeof(GstEditor),
|
||||
sizeof(GstEditorClass),
|
||||
(GtkClassInitFunc)gst_editor_class_init,
|
||||
(GtkObjectInitFunc)gst_editor_init,
|
||||
NULL,
|
||||
NULL,
|
||||
(GtkClassInitFunc)NULL,
|
||||
};
|
||||
editor_type = gtk_type_unique(gtk_frame_get_type(),&editor_info);
|
||||
}
|
||||
return editor_type;
|
||||
}
|
||||
|
||||
static void gst_editor_class_init(GstEditorClass *klass) {
|
||||
GtkObjectClass *object_class;
|
||||
|
||||
object_class = (GtkObjectClass*)klass;
|
||||
|
||||
parent_class = gtk_type_class(gtk_frame_get_type());
|
||||
|
||||
gtk_object_add_arg_type("GstEditor::name",GTK_TYPE_STRING,
|
||||
GTK_ARG_READWRITE,ARG_NAME);
|
||||
|
||||
object_class->set_arg = gst_editor_set_arg;
|
||||
object_class->get_arg = gst_editor_get_arg;
|
||||
}
|
||||
|
||||
static void gst_editor_init(GstEditor *editor) {
|
||||
/* create the pipeline */
|
||||
editor->pipeline = gst_pipeline_new("pipeline");
|
||||
g_return_if_fail(editor->pipeline != NULL);
|
||||
|
||||
/* create the editor canvas */
|
||||
editor->canvas = gst_editor_canvas_new(GST_BIN(editor->pipeline),NULL);
|
||||
|
||||
/* create the scrolled window */
|
||||
editor->scrollwindow = gtk_scrolled_window_new(NULL,NULL);
|
||||
|
||||
/* get the canvas widget */
|
||||
editor->canvaswidget = gst_editor_canvas_get_canvas(editor->canvas);
|
||||
|
||||
/* add the canvas to the scrolled window */
|
||||
gtk_container_add(GTK_CONTAINER(editor->scrollwindow),
|
||||
editor->canvaswidget);
|
||||
|
||||
/* add the scrolled window to the canvas */
|
||||
gtk_container_add(GTK_CONTAINER(editor),editor->scrollwindow);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_editor_new:
|
||||
* name: name of editor frame
|
||||
*
|
||||
* Creates a new GstEditor composite widget with the given name.
|
||||
*
|
||||
* Returns: Freshly created GstEditor widget.
|
||||
*/
|
||||
GstEditor *gst_editor_new(gchar *name) {
|
||||
GstEditor *editor;
|
||||
|
||||
editor = gtk_type_new(gst_editor_get_type());
|
||||
gtk_object_set(GTK_OBJECT(editor),"name",name,NULL);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
static void gst_editor_set_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditor *editor = GST_EDITOR(object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_NAME:
|
||||
gtk_object_set(GTK_OBJECT(editor),"label",GTK_VALUE_STRING(*arg),NULL);
|
||||
gst_element_set_name(GST_OBJECT(editor->pipeline),
|
||||
GTK_VALUE_STRING(*arg));
|
||||
break;
|
||||
default:
|
||||
g_warning("gsteditor: unknown arg!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_editor_get_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditor *editor = GST_EDITOR(object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_NAME:
|
||||
GTK_VALUE_STRING(*arg) =
|
||||
gst_element_get_name(GST_OBJECT(editor->pipeline));
|
||||
break;
|
||||
default:
|
||||
arg->type = GTK_TYPE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
360
editor/gsteditor.h
Normal file
360
editor/gsteditor.h
Normal file
|
@ -0,0 +1,360 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_EDITOR_H__
|
||||
#define __GST_EDITOR_H__
|
||||
|
||||
#include <gnome.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
|
||||
typedef struct _GstEditor GstEditor;
|
||||
typedef struct _GstEditorClass GstEditorClass;
|
||||
typedef struct _GstEditorElement GstEditorElement;
|
||||
typedef struct _GstEditorElementClass GstEditorElementClass;
|
||||
typedef struct _GstEditorBin GstEditorBin;
|
||||
typedef struct _GstEditorBinClass GstEditorBinClass;
|
||||
typedef struct _GstEditorCanvas GstEditorCanvas;
|
||||
typedef struct _GstEditorCanvasClass GstEditorCanvasClass;
|
||||
typedef struct _GstEditorPad GstEditorPad;
|
||||
typedef struct _GstEditorPadClass GstEditorPadClass;
|
||||
typedef struct _GstEditorConnection GstEditorConnection;
|
||||
typedef struct _GstEditorConnectionClass GstEditorConnectionClass;
|
||||
|
||||
|
||||
|
||||
#define GST_TYPE_EDITOR \
|
||||
(gst_editor_get_type())
|
||||
#define GST_EDITOR(obj) \
|
||||
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR,GstEditor))
|
||||
#define GST_EDITOR_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR,GstEditorClass))
|
||||
#define GST_IS_EDITOR(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR))
|
||||
#define GST_IS_EDITOR_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR)))
|
||||
|
||||
|
||||
struct _GstEditor {
|
||||
GtkFrame frame;
|
||||
|
||||
/* the actual pipeline to be associated with this thing */
|
||||
GstPipeline *pipeline;
|
||||
|
||||
/* the editor canvas */
|
||||
GstEditorCanvas *canvas;
|
||||
|
||||
/* the canvas and scrollwindow */
|
||||
GtkWidget *canvaswidget;
|
||||
GtkWidget *scrollwindow;
|
||||
};
|
||||
|
||||
struct _GstEditorClass {
|
||||
GnomeCanvasClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GtkType gst_editor_get_type();
|
||||
GstEditor *gst_editor_new(gchar *name);
|
||||
|
||||
|
||||
|
||||
#define GST_EDITOR_SET_OBJECT(item,object) \
|
||||
(gtk_object_set_data(GTK_OBJECT(item),"gsteditorobject",(object)))
|
||||
#define GST_EDTIOR_GET_OBJECT(item) \
|
||||
(gtk_object_get_data(GTK_OBJECT(item),"gsteditorobject"))
|
||||
|
||||
|
||||
|
||||
#define GST_TYPE_EDITOR_ELEMENT \
|
||||
(gst_editor_element_get_type())
|
||||
#define GST_EDITOR_ELEMENT(obj) \
|
||||
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_ELEMENT,GstEditorElement))
|
||||
#define GST_EDITOR_ELEMENT_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_ELEMENT,GstEditorElementClass))
|
||||
#define GST_IS_EDITOR_ELEMENT(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_ELEMENT))
|
||||
#define GST_IS_EDITOR_ELEMENT_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_ELEMENT)))
|
||||
|
||||
#define GST_EDITOR_ELEMENT_PARENT(obj) (GST_EDITOR_ELEMENT(obj)->parent)
|
||||
#define GST_EDITOR_ELEMENT_GROUP(obj) (GST_EDITOR_ELEMENT(obj)->group)
|
||||
#define GST_EDITOR_ELEMENT_CANVAS(obj) (GST_EDITOR_ELEMENT(obj)->canvas)
|
||||
|
||||
struct _GstEditorElement {
|
||||
GstObject object;
|
||||
|
||||
/* parent object (NULL if I am the parent) */
|
||||
GstEditorBin *parent;
|
||||
|
||||
/* toplevel canvas (myself if I am the toplevel) */
|
||||
GstEditorCanvas *canvas;
|
||||
|
||||
/* the element we're associated with */
|
||||
GstElement *element;
|
||||
|
||||
/* whether we've been realized or not */
|
||||
gboolean realized;
|
||||
|
||||
/* toplevel group, must be !NULL */
|
||||
GnomeCanvasGroup *group; // parent group
|
||||
|
||||
/* visual stuff */
|
||||
gdouble x,y; // center
|
||||
gdouble width,height; // size
|
||||
GnomeCanvasItem *border,*title,*resizebox; // easy ones
|
||||
GnomeCanvasItem *statebox[4],*statetext[4]; // GST_STATE_*
|
||||
GnomeCanvasItem *playbox,*playtext; // playstate
|
||||
gboolean states[5]; // visual states
|
||||
|
||||
gdouble insidewidth,insideheight; // minimum space inside
|
||||
gdouble minwidth,minheight; // minimum size
|
||||
gdouble titlewidth,titleheight; // size of title
|
||||
gdouble statewidth,stateheight; // size of state boxes
|
||||
gdouble sinkwidth,sinkheight; // size of sink pads
|
||||
gdouble srcwidth,srcheight; // size of src pads
|
||||
gint sinks,srcs; // how many pads?
|
||||
|
||||
GnomeCanvasGroup *insidegroup; // contents if any
|
||||
|
||||
gboolean resize; // does it need resizing?
|
||||
|
||||
/* list of pads */
|
||||
GList *srcpads,*sinkpads;
|
||||
gboolean padlistchange;
|
||||
|
||||
/* interaction state */
|
||||
gboolean dragging,resizing,moved,hesitating;
|
||||
gdouble offx,offy,dragx,dragy;
|
||||
};
|
||||
|
||||
struct _GstEditorElementClass {
|
||||
GnomeCanvasGroupClass parent_class;
|
||||
|
||||
void (*realize) (GstEditorElement *element);
|
||||
gint (*event) (GnomeCanvasItem *item,GdkEvent *event,
|
||||
GstEditorElement *element);
|
||||
gint (*button_event) (GnomeCanvasItem *item,GdkEvent *event,
|
||||
GstEditorElement *element);
|
||||
};
|
||||
|
||||
|
||||
GtkType gst_editor_element_get_type();
|
||||
GstEditorElement *gst_editor_element_new(GstEditorBin *parent,
|
||||
GstElement *element,
|
||||
const gchar *first_arg_name,...);
|
||||
void gst_editor_element_construct(GstEditorElement *element,
|
||||
GstEditorBin *parent,
|
||||
const gchar *first_arg_name,
|
||||
va_list args);
|
||||
void gst_editor_element_repack(GstEditorElement *element);
|
||||
GstEditorPad *gst_editor_element_add_pad(GstEditorElement *element,
|
||||
GstPad *pad);
|
||||
|
||||
|
||||
#define GST_TYPE_EDITOR_BIN \
|
||||
(gst_editor_bin_get_type())
|
||||
#define GST_EDITOR_BIN(obj) \
|
||||
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_BIN,GstEditorBin))
|
||||
#define GST_EDITOR_BIN_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_BIN,GstEditorBin))
|
||||
#define GST_IS_EDITOR_BIN(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_BIN))
|
||||
#define GST_IS_EDITOR_BIN_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_BIN)))
|
||||
|
||||
struct _GstEditorBin {
|
||||
GstEditorElement element;
|
||||
|
||||
/* lists of GUI elements and connections */
|
||||
GList *elements, *connections;
|
||||
|
||||
/* connection state */
|
||||
GstEditorPad *frompad; // where the drawing started from
|
||||
gboolean fromsrc; // are we connecting *from* a source?
|
||||
gboolean connecting; // if we're trying to connect right now
|
||||
GstEditorConnection *connection; // the connection we're operating on
|
||||
GstEditorPad *ghostpad; // potential ghost pad
|
||||
gboolean inpadregion; // is cursor in pad region
|
||||
};
|
||||
|
||||
struct _GstEditorBinClass {
|
||||
GstEditorElementClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
|
||||
GtkType gst_editor_bin_get_type();
|
||||
GstEditorBin *gst_editor_bin_new(GstEditorBin *parent,GstBin *bin,
|
||||
const gchar *first_arg_name,...);
|
||||
|
||||
|
||||
|
||||
#define GST_TYPE_EDITOR_CANVAS \
|
||||
(gst_editor_canvas_get_type())
|
||||
#define GST_EDITOR_CANVAS(obj) \
|
||||
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_CANVAS,GstEditorCanvas))
|
||||
#define GST_EDITOR_CANVAS_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_CANVAS,GstEditorCanvasClass))
|
||||
#define GST_IS_EDITOR_CANVAS(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_CANVAS))
|
||||
#define GST_IS_EDITOR_CANVAS_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_CANVAS)))
|
||||
|
||||
|
||||
struct _GstEditorCanvas {
|
||||
GstEditorBin bin;
|
||||
|
||||
gboolean inchild;
|
||||
|
||||
GnomeCanvas *canvas;
|
||||
};
|
||||
|
||||
struct _GstEditorCanvasClass {
|
||||
GnomeCanvasClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GtkType gst_editor_canvas_get_type();
|
||||
GstEditorCanvas *gst_editor_canvas_new(GstBin *bin,
|
||||
const gchar *first_arg_name,...);
|
||||
GtkWidget *gst_editor_canvas_get_canvas(GstEditorCanvas *canvas);
|
||||
void gst_editor_bin_add(GstEditorBin *parent,GstEditorElement *element);
|
||||
|
||||
|
||||
#define GST_TYPE_EDITOR_PAD \
|
||||
(gst_editor_pad_get_type())
|
||||
#define GST_EDITOR_PAD(obj) \
|
||||
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_PAD,GstEditorPad))
|
||||
#define GST_EDITOR_PAD_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_PAD,GstEditorPadClass))
|
||||
#define GST_IS_EDITOR_PAD(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_PAD))
|
||||
#define GST_IS_EDITOR_PAD_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_PAD)))
|
||||
|
||||
struct _GstEditorPad {
|
||||
GtkObject object;
|
||||
|
||||
/* parent element */
|
||||
GstEditorElement *parent;
|
||||
|
||||
/* toplevel canvas */
|
||||
GstEditorCanvas *canvas;
|
||||
|
||||
/* the pad we're associated with */
|
||||
GstPad *pad;
|
||||
/* if this is a sink (convenience) */
|
||||
gboolean issrc;
|
||||
|
||||
/* whether we've been realized or not */
|
||||
gboolean realized;
|
||||
|
||||
/* connections */
|
||||
GstEditorConnection *connection;
|
||||
GstEditorConnection *ghostconnection;
|
||||
|
||||
/* visual stuff */
|
||||
GnomeCanvasGroup *group;
|
||||
GnomeCanvasItem *border,*title,*padbox;
|
||||
gboolean sinkpad; // is this a sink pad?
|
||||
gdouble x,y; // location
|
||||
gdouble width,height; // actual size
|
||||
gdouble boxwidth,boxheight; // size of pad box
|
||||
gboolean resize; // does it need resizing?
|
||||
|
||||
/* interaction state */
|
||||
gboolean dragging,resizing,moved;
|
||||
gdouble dragx,dragy;
|
||||
|
||||
/* connection */
|
||||
// GnomeCanvasItem *connection; // can't use
|
||||
//GstEditorConnection
|
||||
};
|
||||
|
||||
struct _GstEditorPadClass {
|
||||
GtkObjectClass parent_class;
|
||||
|
||||
void (*realize) (GstEditorPad *pad);
|
||||
};
|
||||
|
||||
GtkType gst_editor_pad_get_type();
|
||||
GstEditorPad *gst_editor_pad_new(GstEditorElement *parent,GstPad *pad,
|
||||
const gchar *first_arg_name, ...);
|
||||
void gst_editor_pad_construct(GstEditorPad *element,
|
||||
GstEditorElement *parent,
|
||||
const gchar *first_arg_name,va_list args);
|
||||
void gst_editor_pad_repack(GstEditorPad *pad);
|
||||
|
||||
|
||||
|
||||
#define GST_TYPE_EDITOR_CONNECTION \
|
||||
(gst_editor_connection_get_type())
|
||||
#define GST_EDITOR_CONNECTION(obj) \
|
||||
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_CONNECTION,GstEditorConnection))
|
||||
#define GST_EDITOR_CONNECTION_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_CONNECTION,GstEditorConnectionClass))
|
||||
#define GST_IS_EDITOR_CONNECTION(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_CONNECTION))
|
||||
#define GST_IS_EDITOR_CONNECTION_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_CONNECTION)))
|
||||
|
||||
struct _GstEditorConnection {
|
||||
GtkObject object;
|
||||
|
||||
/* our parent */
|
||||
GstEditorElement *parent;
|
||||
|
||||
/* the two pads we're connecting */
|
||||
GstEditorPad *frompad, *topad;
|
||||
/* is this starting at a source (convenience) */
|
||||
gboolean fromsrc;
|
||||
|
||||
/* toplevel canvas */
|
||||
GstEditorCanvas *canvas;
|
||||
|
||||
/* whether we've been realized or not */
|
||||
gboolean realized;
|
||||
|
||||
/* are we a ghosted connection? */
|
||||
gboolean ghost;
|
||||
|
||||
/* visual stuff */
|
||||
GnomeCanvasItem *line;
|
||||
GnomeCanvasPoints *points;
|
||||
gdouble x,y; // terminating point
|
||||
gboolean resize; // does it need resizing?
|
||||
};
|
||||
|
||||
struct _GstEditorConnectionClass {
|
||||
GtkObjectClass parent_class;
|
||||
void (*realize) (GstEditorConnection *connection);
|
||||
};
|
||||
|
||||
GtkType gst_editor_connection_get_type();
|
||||
void gst_editor_connection_resize(GstEditorConnection *connection);
|
||||
void gst_editor_connection_set_endpoint(GstEditorConnection *connection,
|
||||
gdouble x,gdouble y);
|
||||
void gst_editor_connection_set_endpad(GstEditorConnection *connection,
|
||||
GstEditorPad *pad);
|
||||
void gst_editor_connection_connect(GstEditorConnection *connection);
|
||||
|
||||
|
||||
#endif /* __GST_EDITOR_H__ */
|
266
editor/gsteditorbin.c
Normal file
266
editor/gsteditorbin.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <gnome.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gsteditor.h"
|
||||
|
||||
/* signals and args */
|
||||
enum {
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
};
|
||||
|
||||
static void gst_editor_bin_class_init(GstEditorBinClass *klass);
|
||||
static void gst_editor_bin_init(GstEditorBin *bin);
|
||||
static void gst_editor_bin_set_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_bin_get_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
|
||||
static gint gst_editor_bin_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element);
|
||||
static gint gst_editor_bin_button_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element);
|
||||
|
||||
static GstEditorElementClass *parent_class = NULL;
|
||||
|
||||
GtkType gst_editor_bin_get_type(void) {
|
||||
static GtkType bin_type = 0;
|
||||
|
||||
if (!bin_type) {
|
||||
static const GtkTypeInfo bin_info = {
|
||||
"GstEditorBin",
|
||||
sizeof(GstEditorBin),
|
||||
sizeof(GstEditorBinClass),
|
||||
(GtkClassInitFunc)gst_editor_bin_class_init,
|
||||
(GtkObjectInitFunc)gst_editor_bin_init,
|
||||
NULL,
|
||||
NULL,
|
||||
(GtkClassInitFunc)NULL,
|
||||
};
|
||||
bin_type = gtk_type_unique(gst_editor_element_get_type(),&bin_info);
|
||||
}
|
||||
return bin_type;
|
||||
}
|
||||
|
||||
static void gst_editor_bin_class_init(GstEditorBinClass *klass) {
|
||||
GstEditorElementClass *element_class;
|
||||
|
||||
element_class = (GstEditorElementClass*)klass;
|
||||
|
||||
parent_class = gtk_type_class(gst_editor_element_get_type());
|
||||
|
||||
element_class->event = gst_editor_bin_event;
|
||||
element_class->button_event = gst_editor_bin_button_event;
|
||||
}
|
||||
|
||||
static void gst_editor_bin_init(GstEditorBin *bin) {
|
||||
GstEditorElement *element = GST_EDITOR_ELEMENT(bin);
|
||||
|
||||
element->insidewidth = 200;
|
||||
element->insideheight = 100;
|
||||
}
|
||||
|
||||
GstEditorBin *gst_editor_bin_new(GstEditorBin *parent,GstBin *bin,
|
||||
const gchar *first_arg_name,...) {
|
||||
GstEditorBin *editorbin;
|
||||
va_list args;
|
||||
|
||||
g_return_if_fail(parent != NULL);
|
||||
g_return_if_fail(GST_IS_EDITOR_BIN(parent));
|
||||
g_return_if_fail(bin != NULL);
|
||||
g_return_if_fail(GST_IS_BIN(bin));
|
||||
|
||||
editorbin = GST_EDITOR_BIN(gtk_type_new(GST_TYPE_EDITOR_BIN));
|
||||
GST_EDITOR_ELEMENT(editorbin)->element = GST_ELEMENT(bin);
|
||||
|
||||
va_start(args,first_arg_name);
|
||||
gst_editor_element_construct(GST_EDITOR_ELEMENT(editorbin),parent,
|
||||
first_arg_name,args);
|
||||
va_end(args);
|
||||
|
||||
return editorbin;
|
||||
}
|
||||
|
||||
|
||||
static gint gst_editor_bin_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element) {
|
||||
GstEditorBin *bin = GST_EDITOR_BIN(element);
|
||||
|
||||
// g_print("bin got %d event at %.2fx%.2f\n",event->type,
|
||||
// event->button.x,event->button.y);
|
||||
|
||||
switch (event->type) {
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (bin->connecting) {
|
||||
// g_print("bin got release event during drag\n");
|
||||
gnome_canvas_item_ungrab(
|
||||
GNOME_CANVAS_ITEM(element->group),
|
||||
event->button.time);
|
||||
if (bin->connection->topad)
|
||||
gst_editor_connection_connect(bin->connection);
|
||||
else {
|
||||
bin->connection->frompad->connection = NULL;
|
||||
g_list_remove(bin->connections,bin->connection);
|
||||
gtk_object_destroy(GTK_OBJECT(bin->connection));
|
||||
bin->connection = NULL;
|
||||
}
|
||||
bin->connecting = FALSE;
|
||||
//g_print("in bin, setting inchild for button release\n");
|
||||
element->canvas->inchild = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if (bin->connecting) {
|
||||
gdouble x,y;
|
||||
x = event->button.x;y = event->button.y;
|
||||
// g_print("bin has motion during connection draw at %.2fx%.2f\n",
|
||||
// x,y);
|
||||
gst_editor_bin_connection_drag(bin,x,y);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (GST_EDITOR_ELEMENT_CLASS(parent_class)->event)
|
||||
return (*GST_EDITOR_ELEMENT_CLASS(parent_class)->event)(item,event,element);
|
||||
}
|
||||
|
||||
|
||||
static gint gst_editor_bin_button_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element) {
|
||||
GstEditorBin *bin = GST_EDITOR_BIN(element);
|
||||
GstEditorElement *newelement;
|
||||
|
||||
// g_print("bin got button event\n");
|
||||
|
||||
if (event->type != GDK_BUTTON_RELEASE) return FALSE;
|
||||
|
||||
gnome_canvas_item_w2i(item,&event->button.x,&event->button.y);
|
||||
// g_print("calling gst_editor_create_item(,%.2f,%.2f)\n",
|
||||
// event->button.x,event->button.y);
|
||||
newelement = gst_editor_create_item(bin,event->button.x,event->button.y);
|
||||
if (newelement != NULL);
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void gst_editor_bin_start_banding(GstEditorBin *bin,GstEditorPad *pad) {
|
||||
GdkCursor *cursor;
|
||||
|
||||
// g_print("starting to band\n");
|
||||
|
||||
g_return_if_fail(GST_IS_EDITOR_PAD(pad));
|
||||
|
||||
bin->connection = gst_editor_connection_new(bin,pad);
|
||||
bin->connections = g_list_prepend(bin->connections,bin->connection);
|
||||
cursor = gdk_cursor_new(GDK_SB_RIGHT_ARROW);
|
||||
gnome_canvas_item_grab(
|
||||
GNOME_CANVAS_ITEM(GST_EDITOR_ELEMENT(bin)->group),
|
||||
GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
|
||||
cursor,GDK_CURRENT_TIME);
|
||||
|
||||
bin->connecting = TRUE;
|
||||
}
|
||||
|
||||
|
||||
void gst_editor_bin_connection_drag(GstEditorBin *bin,
|
||||
gdouble wx,gdouble wy) {
|
||||
GstEditorElement *element;
|
||||
gdouble bx,by;
|
||||
GnomeCanvasItem *underitem, *under = NULL;
|
||||
GstEditorPad *destpad;
|
||||
|
||||
element = GST_EDITOR_ELEMENT(bin);
|
||||
|
||||
bx = wx;by = wy;
|
||||
gnome_canvas_item_w2i(GST_EDITOR_ELEMENT(bin)->group,&bx,&by);
|
||||
|
||||
// first see if we're on top of an interesting pad
|
||||
underitem = gnome_canvas_get_item_at(
|
||||
GST_EDITOR_ELEMENT(bin)->canvas->canvas,wx,wy);
|
||||
if (underitem != NULL)
|
||||
under = GST_EDTIOR_GET_OBJECT(underitem);
|
||||
if ((under != NULL) && GST_IS_EDITOR_PAD(under)) {
|
||||
destpad = GST_EDITOR_PAD(under);
|
||||
if (destpad != bin->connection->frompad)
|
||||
gst_editor_connection_set_endpad(bin->connection,destpad);
|
||||
} else {
|
||||
gst_editor_connection_set_endpoint(bin->connection,bx,by);
|
||||
}
|
||||
|
||||
/* This code is a nightmare, it'll be fixed in the next minor version
|
||||
if (
|
||||
((bx < element->sinkwidth) ||
|
||||
(bx > (element->width - element->srcwidth))) &&
|
||||
((by > element->titleheight) &&
|
||||
(by < (element->height - element->stateheight)))
|
||||
) {
|
||||
if (!bin->inpadregion) {
|
||||
GstEditorPad *ghostpad;
|
||||
g_print("I'd be creating a ghost pad right about now...\n");
|
||||
gst_element_add_ghost_pad(
|
||||
GST_EDITOR_ELEMENT(bin)->element,
|
||||
bin->connection->frompad->pad);
|
||||
ghostpad = gst_editor_element_add_pad(GST_EDITOR_ELEMENT(bin),
|
||||
bin->connection->frompad->pad);
|
||||
gst_editor_connection_set_endpad(bin->connection,ghostpad);
|
||||
gtk_object_set(GTK_OBJECT(bin->connection),"ghost",TRUE,NULL);
|
||||
bin->inpadregion = TRUE;
|
||||
} else {
|
||||
g_print("I'd be moving the ghost pad around now...\n");
|
||||
}
|
||||
} else {
|
||||
if (bin->inpadregion) {
|
||||
g_print("I'd be removing the ghost pad now...\n");
|
||||
bin->inpadregion = FALSE;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void gst_editor_bin_add(GstEditorBin *bin,GstEditorElement *element) {
|
||||
/* set the element's parent */
|
||||
element->parent = bin;
|
||||
|
||||
/* set the canvas */
|
||||
if (GST_IS_EDITOR_CANVAS(bin))
|
||||
element->canvas = GST_EDITOR_CANVAS(bin);
|
||||
else
|
||||
element->canvas = GST_EDITOR_ELEMENT(bin)->canvas;
|
||||
|
||||
/* add element to list of bin's children */
|
||||
bin->elements = g_list_prepend(bin->elements,element);
|
||||
|
||||
/* add the real element to the real bin */
|
||||
gst_bin_add(GST_BIN(GST_EDITOR_ELEMENT(bin)->element),element->element);
|
||||
}
|
251
editor/gsteditorcanvas.c
Normal file
251
editor/gsteditorcanvas.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <gnome.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gsteditor.h"
|
||||
|
||||
/* signals and args */
|
||||
enum {
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_CANVAS,
|
||||
};
|
||||
|
||||
static void gst_editor_canvas_class_init(GstEditorCanvasClass *klass);
|
||||
static void gst_editor_canvas_init(GstEditorCanvas *editorcanvas);
|
||||
static void gst_editor_canvas_set_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_canvas_get_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_canvas_realize(GstEditorElement *element);
|
||||
|
||||
|
||||
static gint gst_editor_canvas_button_release(GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GstEditorCanvas *canvas);
|
||||
static gint gst_editor_canvas_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element);
|
||||
|
||||
//gint gst_editor_canvas_verbose_event(GtkWidget *widget,GdkEvent *event);
|
||||
|
||||
|
||||
static GstEditorBinClass *parent_class = NULL;
|
||||
|
||||
GtkType gst_editor_canvas_get_type(void) {
|
||||
static GtkType editor_canvas_type = 0;
|
||||
|
||||
if (!editor_canvas_type) {
|
||||
static const GtkTypeInfo editor_canvas_info = {
|
||||
"GstEditorCanvas",
|
||||
sizeof(GstEditorCanvas),
|
||||
sizeof(GstEditorCanvasClass),
|
||||
(GtkClassInitFunc)gst_editor_canvas_class_init,
|
||||
(GtkObjectInitFunc)gst_editor_canvas_init,
|
||||
NULL,
|
||||
NULL,
|
||||
(GtkClassInitFunc)NULL,
|
||||
};
|
||||
editor_canvas_type = gtk_type_unique(gst_editor_bin_get_type(),&editor_canvas_info);
|
||||
}
|
||||
return editor_canvas_type;
|
||||
}
|
||||
|
||||
static void gst_editor_canvas_class_init(GstEditorCanvasClass *klass) {
|
||||
GstEditorElementClass *element_class;
|
||||
|
||||
element_class = (GstEditorElementClass*)klass;
|
||||
|
||||
parent_class = gtk_type_class(gst_editor_bin_get_type());
|
||||
|
||||
gtk_object_add_arg_type("GstEditorCanvas::canvas",GTK_TYPE_POINTER,
|
||||
GTK_ARG_READABLE,ARG_CANVAS);
|
||||
|
||||
element_class->realize = gst_editor_canvas_realize;
|
||||
}
|
||||
|
||||
static void gst_editor_canvas_init(GstEditorCanvas *editorcanvas) {
|
||||
}
|
||||
|
||||
GstEditorCanvas *gst_editor_canvas_new(GstBin *bin,
|
||||
const gchar *first_arg_name,...) {
|
||||
GstEditorCanvas *editorcanvas;
|
||||
va_list args;
|
||||
|
||||
g_return_if_fail(bin != NULL);
|
||||
g_return_if_fail(GST_IS_BIN(bin));
|
||||
|
||||
editorcanvas = GST_EDITOR_CANVAS(gtk_type_new(GST_TYPE_EDITOR_CANVAS));
|
||||
GST_EDITOR_ELEMENT(editorcanvas)->element = GST_ELEMENT(bin);
|
||||
|
||||
va_start(args,first_arg_name);
|
||||
gst_editor_element_construct(GST_EDITOR_ELEMENT(editorcanvas),NULL,
|
||||
first_arg_name,args);
|
||||
va_end(args);
|
||||
|
||||
return editorcanvas;
|
||||
}
|
||||
|
||||
static void gst_editor_canvas_realize(GstEditorElement *element) {
|
||||
GstEditorCanvas *canvas = GST_EDITOR_CANVAS(element);
|
||||
|
||||
canvas->canvas = GNOME_CANVAS(gnome_canvas_new());
|
||||
element->canvas = canvas;
|
||||
gtk_signal_connect(GTK_OBJECT(canvas->canvas),
|
||||
"event",
|
||||
GTK_SIGNAL_FUNC(gst_editor_canvas_event),
|
||||
canvas);
|
||||
gtk_signal_connect_after(GTK_OBJECT(canvas->canvas),
|
||||
"button_release_event",
|
||||
GTK_SIGNAL_FUNC(gst_editor_canvas_button_release),
|
||||
canvas);
|
||||
GST_EDITOR_SET_OBJECT(canvas->canvas,canvas);
|
||||
|
||||
element->group = gnome_canvas_root(canvas->canvas);
|
||||
|
||||
gnome_canvas_item_new(element->group,gnome_canvas_rect_get_type(),
|
||||
"width_units",1.0,"fill_color","white",
|
||||
"outline_color","black",
|
||||
"x1",-2.0,"y1",-2.0,"x2",2.0,"y2",2.0,NULL);
|
||||
}
|
||||
|
||||
static void gst_editor_canvas_set_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditorCanvas *canvas;
|
||||
|
||||
canvas = GST_EDITOR_CANVAS(object);
|
||||
|
||||
switch (id) {
|
||||
default:
|
||||
g_warning("gsteditorcanvas: unknown arg!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_editor_canvas_get_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditorCanvas *canvas;
|
||||
|
||||
canvas = GST_EDITOR_CANVAS(object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_CANVAS:
|
||||
GTK_VALUE_POINTER(*arg) = canvas->canvas;
|
||||
break;
|
||||
default:
|
||||
arg->type = GTK_TYPE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *gst_editor_canvas_get_canvas(GstEditorCanvas *canvas) {
|
||||
return GTK_WIDGET(canvas->canvas);
|
||||
}
|
||||
|
||||
|
||||
static gint gst_editor_canvas_button_release(GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GstEditorCanvas *canvas) {
|
||||
GstEditorBin *bin = GST_EDITOR_BIN(canvas);
|
||||
gdouble x,y;
|
||||
GstEditorElement *element;
|
||||
|
||||
// g_print("canvas got button press at %.2fx%.2f\n",
|
||||
// event->button.x,event->button.y);
|
||||
if (event->type != GDK_BUTTON_RELEASE) return FALSE;
|
||||
|
||||
// if we're connecting a pair of objects in the canvas, fall through
|
||||
// if (bin->connection) {
|
||||
// g_print("we're in a connection, not handling\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
if (canvas->inchild) {
|
||||
// g_print("inchild, not responding to button_release\n");
|
||||
canvas->inchild = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gnome_canvas_window_to_world(GNOME_CANVAS(widget),
|
||||
event->button.x,event->button.y,&x,&y);
|
||||
// g_print("calling gst_editor_create_item()\n");
|
||||
if (element = gst_editor_create_item(GST_EDITOR_BIN(canvas),x,y))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: guerilla prototype... */
|
||||
void gst_editor_bin_connection_drag(GstEditorBin *bin,
|
||||
gdouble wx,gdouble wy);
|
||||
|
||||
static gint gst_editor_canvas_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element) {
|
||||
// if (GST_EDITOR_ELEMENT_CLASS(parent_class)->event)
|
||||
// return (*GST_EDITOR_ELEMENT_CLASS(parent_class)->event)(
|
||||
// element->group,event,element);
|
||||
|
||||
GstEditorBin *bin = GST_EDITOR_BIN(element);
|
||||
GstEditorCanvas *canvas = GST_EDITOR_CANVAS(element);
|
||||
|
||||
// g_print("canvas got event %d at %.2fx%.2f\n",event->type,
|
||||
// event->button.x,event->button.y);
|
||||
|
||||
switch (event->type) {
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (bin->connecting) {
|
||||
// g_print("canvas got button release during drag\n");
|
||||
gnome_canvas_item_ungrab(
|
||||
GNOME_CANVAS_ITEM(element->group),
|
||||
event->button.time);
|
||||
if (bin->connection->topad)
|
||||
gst_editor_connection_connect(bin->connection);
|
||||
else
|
||||
gtk_object_destroy(GTK_OBJECT(bin->connection));
|
||||
bin->connecting = FALSE;
|
||||
//g_print("finished dragging connection on canvas, setting inchild\n");
|
||||
element->canvas->inchild = TRUE;
|
||||
return TRUE;
|
||||
} else {
|
||||
// g_print("got release, calling button_release()\n");
|
||||
// gst_editor_canvas_button_release(canvas->canvas,event,canvas);
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if (bin->connecting) {
|
||||
gdouble x,y;
|
||||
x = event->button.x;y = event->button.y;
|
||||
gnome_canvas_window_to_world(canvas->canvas,
|
||||
event->button.x,event->button.y,&x,&y);
|
||||
// g_print("canvas has motion during connection draw at
|
||||
//%.2fx%.2f\n",
|
||||
// x,y);
|
||||
gst_editor_bin_connection_drag(bin,x,y);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
289
editor/gsteditorconnection.c
Normal file
289
editor/gsteditorconnection.c
Normal file
|
@ -0,0 +1,289 @@
|
|||
#include <gnome.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/gstutils.h>
|
||||
|
||||
#include "gsteditor.h"
|
||||
|
||||
/* class functions */
|
||||
static void gst_editor_connection_class_init(GstEditorConnectionClass *klass);
|
||||
static void gst_editor_connection_init(GstEditorConnection *connection);
|
||||
static void gst_editor_connection_set_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_connection_get_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_connection_destroy(GtkObject *object);
|
||||
static void gst_editor_connection_realize(GstEditorConnection *connection);
|
||||
|
||||
/* events fired by items within self */
|
||||
static gint gst_editor_connection_line_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorConnection *connection);
|
||||
|
||||
/* utility functions */
|
||||
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_X,
|
||||
ARG_Y,
|
||||
ARG_FROMPAD,
|
||||
ARG_TOPAD,
|
||||
ARG_GHOST,
|
||||
};
|
||||
|
||||
enum {
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static GtkObjectClass *parent_class;
|
||||
static guint gst_editor_connection_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
GtkType gst_editor_connection_get_type() {
|
||||
static GtkType connection_type = 0;
|
||||
|
||||
if (!connection_type) {
|
||||
static const GtkTypeInfo connection_info = {
|
||||
"GstEditorConnection",
|
||||
sizeof(GstEditorConnection),
|
||||
sizeof(GstEditorConnectionClass),
|
||||
(GtkClassInitFunc)gst_editor_connection_class_init,
|
||||
(GtkObjectInitFunc)gst_editor_connection_init,
|
||||
NULL,
|
||||
NULL,
|
||||
(GtkClassInitFunc)NULL,
|
||||
};
|
||||
connection_type = gtk_type_unique(gtk_object_get_type(),&connection_info);
|
||||
}
|
||||
return connection_type;
|
||||
}
|
||||
|
||||
static void gst_editor_connection_class_init(GstEditorConnectionClass *klass) {
|
||||
GtkObjectClass *object_class;
|
||||
|
||||
object_class = (GtkObjectClass*)klass;
|
||||
|
||||
parent_class = gtk_type_class(gnome_canvas_line_get_type());
|
||||
|
||||
gtk_object_add_arg_type("GstEditorConnection::x",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_X);
|
||||
gtk_object_add_arg_type("GstEditorConnection::y",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_Y);
|
||||
gtk_object_add_arg_type("GstEditorConnection::frompad",GTK_TYPE_POINTER,
|
||||
GTK_ARG_READWRITE,ARG_FROMPAD);
|
||||
gtk_object_add_arg_type("GstEditorConnection::topad",GTK_TYPE_POINTER,
|
||||
GTK_ARG_READWRITE,ARG_TOPAD);
|
||||
gtk_object_add_arg_type("GstEditorConnection::ghost",GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE,ARG_GHOST);
|
||||
|
||||
klass->realize = gst_editor_connection_realize;
|
||||
|
||||
object_class->set_arg = gst_editor_connection_set_arg;
|
||||
object_class->get_arg = gst_editor_connection_get_arg;
|
||||
object_class->destroy = gst_editor_connection_destroy;
|
||||
}
|
||||
|
||||
static void gst_editor_connection_init(GstEditorConnection *connection) {
|
||||
connection->points = gnome_canvas_points_new(2);
|
||||
}
|
||||
|
||||
GstEditorConnection *gst_editor_connection_new(GstEditorBin *parent,
|
||||
GstEditorPad *frompad) {
|
||||
GstEditorConnection *connection;
|
||||
|
||||
g_return_if_fail(parent != NULL);
|
||||
g_return_if_fail(GST_IS_EDITOR_BIN(parent));
|
||||
g_return_if_fail(frompad != NULL);
|
||||
g_return_if_fail(GST_IS_EDITOR_PAD(frompad));
|
||||
|
||||
connection = GST_EDITOR_CONNECTION(gtk_type_new(GST_TYPE_EDITOR_CONNECTION));
|
||||
connection->frompad = frompad;
|
||||
connection->frompad->connection = connection;
|
||||
connection->fromsrc = connection->frompad->issrc;
|
||||
connection->parent = parent;
|
||||
|
||||
gst_editor_connection_realize(connection);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
static void gst_editor_connection_set_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditorConnection *connection;
|
||||
|
||||
/* get the major types of this object */
|
||||
connection = GST_EDITOR_CONNECTION(object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_X:
|
||||
connection->x = GTK_VALUE_DOUBLE(*arg);
|
||||
connection->resize = TRUE;
|
||||
break;
|
||||
case ARG_Y:
|
||||
connection->y = GTK_VALUE_DOUBLE(*arg);
|
||||
connection->resize = TRUE;
|
||||
break;
|
||||
case ARG_TOPAD:
|
||||
if (connection->topad) {
|
||||
if (connection->ghost)
|
||||
connection->topad->ghostconnection = NULL;
|
||||
else
|
||||
connection->topad->connection = NULL;
|
||||
}
|
||||
connection->topad = GTK_VALUE_POINTER(*arg);
|
||||
/* if this is the same type, refuse */
|
||||
if (connection->topad &&
|
||||
(connection->frompad->issrc == connection->topad->issrc))
|
||||
connection->topad = NULL;
|
||||
if (connection->topad) {
|
||||
if (connection->ghost)
|
||||
connection->topad->ghostconnection = connection;
|
||||
else
|
||||
connection->topad->connection = connection;
|
||||
}
|
||||
connection->resize = TRUE;
|
||||
break;
|
||||
case ARG_GHOST:
|
||||
connection->ghost = GTK_VALUE_BOOL(*arg);
|
||||
break;
|
||||
default:
|
||||
g_warning("gsteditorconnection: unknown arg!");
|
||||
break;
|
||||
}
|
||||
gst_editor_connection_resize(connection);
|
||||
}
|
||||
|
||||
static void gst_editor_connection_get_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditorConnection *connection;
|
||||
|
||||
/* get the major types of this object */
|
||||
connection = GST_EDITOR_CONNECTION(object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_X:
|
||||
GTK_VALUE_INT(*arg) = connection->x;
|
||||
break;
|
||||
case ARG_Y:
|
||||
GTK_VALUE_INT(*arg) = connection->y;
|
||||
break;
|
||||
default:
|
||||
arg->type = GTK_TYPE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gst_editor_connection_realize(GstEditorConnection *connection) {
|
||||
connection->points->coords[0] = 0.0;
|
||||
connection->points->coords[1] = 0.0;
|
||||
connection->points->coords[2] = 0.0;
|
||||
connection->points->coords[3] = 0.0;
|
||||
connection->line = gnome_canvas_item_new(
|
||||
GST_EDITOR_ELEMENT(connection->parent)->group,
|
||||
gnome_canvas_line_get_type(),
|
||||
"points",connection->points,NULL);
|
||||
}
|
||||
|
||||
static void gst_editor_connection_destroy(GtkObject *object) {
|
||||
GstEditorConnection *connection = GST_EDITOR_CONNECTION(object);
|
||||
|
||||
gtk_object_destroy(GTK_OBJECT(connection->line));
|
||||
}
|
||||
|
||||
void gst_editor_connection_resize(GstEditorConnection *connection) {
|
||||
gdouble x1,y1,x2,y2;
|
||||
|
||||
if (connection->resize != TRUE) return;
|
||||
connection->resize = FALSE;
|
||||
|
||||
// g_print("resizing connection, frompad is %p, topad is %p\n",
|
||||
// connection->frompad,connection->topad);
|
||||
|
||||
/* calculate the new endpoints */
|
||||
if (connection->topad == NULL) {
|
||||
/* our base point is the source pad */
|
||||
if (connection->fromsrc)
|
||||
x1 = connection->frompad->x + connection->frompad->width;
|
||||
else
|
||||
x1 = connection->frompad->x;
|
||||
y1 = connection->frompad->y + (connection->frompad->height / 2);
|
||||
x2 = connection->x;
|
||||
y2 = connection->y;
|
||||
/* NOTE: coords are in the following state:
|
||||
x1,y1: item coords relative to the element's group
|
||||
x2,y2: item coords relative to the bin's group
|
||||
This means translating the x1,y1 coords into world, then into bin.
|
||||
*/
|
||||
gnome_canvas_item_i2w(connection->frompad->parent->group,&x1,&y1);
|
||||
gnome_canvas_item_w2i(GST_EDITOR_ELEMENT_GROUP(connection->parent),
|
||||
&x1,&y1);
|
||||
} else {
|
||||
if (connection->fromsrc) {
|
||||
x1 = connection->frompad->x + connection->frompad->width;
|
||||
x2 = connection->topad->x;
|
||||
} else {
|
||||
x1 = connection->frompad->x;
|
||||
x2 = connection->topad->x + connection->topad->width;
|
||||
}
|
||||
y1 = connection->frompad->y + (connection->frompad->height / 2);
|
||||
y2 = connection->topad->y + (connection->topad->height / 2);
|
||||
gnome_canvas_item_i2w(connection->frompad->parent->group,&x1,&y1);
|
||||
gnome_canvas_item_w2i(GST_EDITOR_ELEMENT_GROUP(connection->parent),
|
||||
&x1,&y1);
|
||||
gnome_canvas_item_i2w(connection->topad->parent->group,&x2,&y2);
|
||||
gnome_canvas_item_w2i(GST_EDITOR_ELEMENT_GROUP(connection->parent),
|
||||
&x2,&y2);
|
||||
}
|
||||
|
||||
connection->points->coords[0] = x1;
|
||||
connection->points->coords[1] = y1;
|
||||
connection->points->coords[2] = x2;
|
||||
connection->points->coords[3] = y2;
|
||||
gnome_canvas_item_set(connection->line,
|
||||
"points",connection->points,NULL);
|
||||
}
|
||||
|
||||
void gst_editor_connection_set_endpoint(GstEditorConnection *connection,
|
||||
gdouble x,gdouble y) {
|
||||
connection->x = x;
|
||||
connection->y = y;
|
||||
if (connection->topad) {
|
||||
if (connection->ghost)
|
||||
connection->topad->ghostconnection = NULL;
|
||||
else
|
||||
connection->topad->connection = NULL;
|
||||
connection->topad = NULL;
|
||||
}
|
||||
connection->resize = TRUE;
|
||||
gst_editor_connection_resize(connection);
|
||||
}
|
||||
|
||||
void gst_editor_connection_set_endpad(GstEditorConnection *connection,
|
||||
GstEditorPad *pad) {
|
||||
// first check for the trivial case
|
||||
if (connection->topad == pad) return;
|
||||
|
||||
// now clean up if we've changed pads
|
||||
if (connection->topad) {
|
||||
if (connection->ghost)
|
||||
connection->topad->ghostconnection = NULL;
|
||||
else
|
||||
connection->topad->connection = NULL;
|
||||
}
|
||||
connection->topad = pad;
|
||||
if (connection->ghost)
|
||||
connection->topad->ghostconnection = connection;
|
||||
else
|
||||
connection->topad->connection = connection;
|
||||
connection->resize = TRUE;
|
||||
gst_editor_connection_resize(connection);
|
||||
}
|
||||
|
||||
void gst_editor_connection_connect(GstEditorConnection *connection) {
|
||||
if (connection->ghost) {
|
||||
g_print("uhhh.... Boo!\n");
|
||||
} else {
|
||||
if (connection->fromsrc)
|
||||
gst_pad_connect(connection->frompad->pad,connection->topad->pad);
|
||||
else
|
||||
gst_pad_connect(connection->topad->pad,connection->frompad->pad);
|
||||
}
|
||||
}
|
61
editor/gsteditorconnection.h
Normal file
61
editor/gsteditorconnection.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_EDITOR_CONNECTION_H__
|
||||
#define __GST_EDITOR_CONNECTION_H__
|
||||
|
||||
#include <gnome.h>
|
||||
#include <gst.h>
|
||||
|
||||
#define GST_TYPE_EDITOR_CONNECTION \
|
||||
(gst_editor_connection_get_type())
|
||||
#define GST_EDITOR_CONNECTION(obj) \
|
||||
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_CONNECTION,GstEditorConnection))
|
||||
#define GST_EDITOR_CONNECTION_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_CONNECTION,GstEditorConnection))
|
||||
#define GST_IS_EDITOR_CONNECTION(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_CONNECTION))
|
||||
#define GST_IS_EDITOR_CONNECTION_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_CONNECTION)))
|
||||
|
||||
typedef struct _GstEditorConnection GstEditorConnection;
|
||||
typedef struct _GstEditorConnectionClass GstEditorConnectionClass;
|
||||
|
||||
struct _GstEditorConnection {
|
||||
GnomeCanvasLine line;
|
||||
|
||||
/* the two pads we're connecting */
|
||||
GstEditorPad *pad1, *pad2;
|
||||
gdouble fromsrc;
|
||||
|
||||
/* visual stuff */
|
||||
gdouble x,y; // terminating point
|
||||
GnomeCanvasPoints *points;
|
||||
gboolean created; // has it been created?
|
||||
gboolean resized; // does it need resizing?
|
||||
};
|
||||
|
||||
struct _GstEditorConnectionClass {
|
||||
GnomeCanvasGroupClass parent_class;
|
||||
};
|
||||
|
||||
GtkType gst_editor_connection_get_type();
|
||||
|
||||
#endif /* __GST_EDITOR_CONNECTION_H__ */
|
57
editor/gsteditorcreate.c
Normal file
57
editor/gsteditorcreate.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <gnome.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gsteditor.h"
|
||||
#include "gstelementselect.h"
|
||||
|
||||
GstEditorElement *gst_editor_create_item(GstEditorBin *bin,
|
||||
gdouble x,gdouble y) {
|
||||
GstElementFactory *factory;
|
||||
GstElement *element;
|
||||
GstEditorElement *editorelement;
|
||||
GtkType itemtype;
|
||||
|
||||
factory = element_select_dialog();
|
||||
if (factory) {
|
||||
// g_print("got factory \"%s\"\n",factory->name);
|
||||
element = gst_elementfactory_create(factory,factory->name);
|
||||
if (element) {
|
||||
if (GST_IS_BIN(element)) {
|
||||
// g_print("factory is a bin\n");
|
||||
editorelement = GST_EDITOR_ELEMENT(gst_editor_bin_new(
|
||||
GST_EDITOR_BIN(bin),GST_BIN(element),
|
||||
"x",x,"y",y,"width",50.0,"height",20.0,NULL));
|
||||
} else {
|
||||
// g_print("factory is an element\n");
|
||||
editorelement = gst_editor_element_new(bin,element,
|
||||
"x",x,"y",y,"width",50.0,"height",20.0,NULL);
|
||||
}
|
||||
// g_print("created element \"%s\" at %.2fx%.2f\n",
|
||||
// gst_object_get_name(GST_OBJECT(element)),
|
||||
// x,y);
|
||||
return editorelement;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
24
editor/gsteditorcreate.h
Normal file
24
editor/gsteditorcreate.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include "gsteditor.h"
|
||||
|
||||
GstEditorElement *gst_editor_create_item(GstEditorBin *bin,
|
||||
gdouble x,gdouble y);
|
927
editor/gsteditorelement.c
Normal file
927
editor/gsteditorelement.c
Normal file
|
@ -0,0 +1,927 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <gnome.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/gstutils.h>
|
||||
|
||||
#include "gsteditor.h"
|
||||
|
||||
/* class functions */
|
||||
static void gst_editor_element_class_init(GstEditorElementClass *klass);
|
||||
static void gst_editor_element_init(GstEditorElement *element);
|
||||
static void gst_editor_element_set_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_element_get_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_element_realize(GstEditorElement *element);
|
||||
static gint gst_editor_element_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element);
|
||||
|
||||
/* events fired by items within self */
|
||||
static gint gst_editor_element_resizebox_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element);
|
||||
static gint gst_editor_element_group_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element);
|
||||
static gint gst_editor_element_state_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
gpointer data);
|
||||
|
||||
/* external events (from GstElement) */
|
||||
static void gst_editor_element_state_change(GstElement *element,
|
||||
gint state,
|
||||
GstEditorElement *editorelement);
|
||||
|
||||
/* utility functions */
|
||||
static void gst_editor_element_resize(GstEditorElement *element);
|
||||
static void gst_editor_element_set_state(GstEditorElement *element,
|
||||
gint id,gboolean set);
|
||||
static void gst_editor_element_sync_state(GstEditorElement *element);
|
||||
static void gst_editor_element_move(GstEditorElement *element,
|
||||
gdouble dx,gdouble dy);
|
||||
|
||||
|
||||
static gchar *_gst_editor_element_states[] = { "C","R","D","P" };
|
||||
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_X,
|
||||
ARG_Y,
|
||||
ARG_WIDTH,
|
||||
ARG_HEIGHT,
|
||||
ARG_X1,
|
||||
ARG_Y1,
|
||||
ARG_X2,
|
||||
ARG_Y2,
|
||||
ARG_ELEMENT,
|
||||
};
|
||||
|
||||
enum {
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static GtkObjectClass *parent_class;
|
||||
static guint gst_editor_element_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
GtkType gst_editor_element_get_type() {
|
||||
static GtkType element_type = 0;
|
||||
|
||||
if (!element_type) {
|
||||
static const GtkTypeInfo element_info = {
|
||||
"GstEditorElement",
|
||||
sizeof(GstEditorElement),
|
||||
sizeof(GstEditorElementClass),
|
||||
(GtkClassInitFunc)gst_editor_element_class_init,
|
||||
(GtkObjectInitFunc)gst_editor_element_init,
|
||||
NULL,
|
||||
NULL,
|
||||
(GtkClassInitFunc)NULL,
|
||||
};
|
||||
element_type = gtk_type_unique(gtk_object_get_type(),&element_info);
|
||||
}
|
||||
return element_type;
|
||||
}
|
||||
|
||||
static void gst_editor_element_class_init(GstEditorElementClass *klass) {
|
||||
GtkObjectClass *object_class;
|
||||
|
||||
object_class = (GtkObjectClass*)klass;
|
||||
|
||||
parent_class = gtk_type_class(gtk_object_get_type());
|
||||
|
||||
gtk_object_add_arg_type("GstEditorElement::x",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY,
|
||||
ARG_X);
|
||||
gtk_object_add_arg_type("GstEditorElement::y",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY,
|
||||
ARG_Y);
|
||||
gtk_object_add_arg_type("GstEditorElement::width",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY,
|
||||
ARG_WIDTH);
|
||||
gtk_object_add_arg_type("GstEditorElement::height",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY,
|
||||
ARG_HEIGHT);
|
||||
gtk_object_add_arg_type("GstEditorElement::x1",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_X1);
|
||||
gtk_object_add_arg_type("GstEditorElement::y1",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_Y1);
|
||||
gtk_object_add_arg_type("GstEditorElement::x2",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_X2);
|
||||
gtk_object_add_arg_type("GstEditorElement::y2",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_Y2);
|
||||
gtk_object_add_arg_type("GstEditorElement::element",GTK_TYPE_POINTER,
|
||||
GTK_ARG_READABLE,ARG_ELEMENT);
|
||||
|
||||
klass->realize = gst_editor_element_realize;
|
||||
klass->event = gst_editor_element_event;
|
||||
|
||||
object_class->set_arg = gst_editor_element_set_arg;
|
||||
object_class->get_arg = gst_editor_element_get_arg;
|
||||
}
|
||||
|
||||
static void gst_editor_element_init(GstEditorElement *element) {
|
||||
}
|
||||
|
||||
GstEditorElement *gst_editor_element_new(GstEditorBin *parent,
|
||||
GstElement *element,
|
||||
const gchar *first_arg_name, ...) {
|
||||
GstEditorElement *editorelement;
|
||||
va_list args;
|
||||
|
||||
g_return_if_fail(parent != NULL);
|
||||
g_return_if_fail(GST_IS_EDITOR_BIN(parent));
|
||||
g_return_if_fail(element != NULL);
|
||||
g_return_if_fail(GST_IS_ELEMENT(element));
|
||||
|
||||
editorelement = GST_EDITOR_ELEMENT(gtk_type_new(GST_TYPE_EDITOR_ELEMENT));
|
||||
editorelement->element = element;
|
||||
|
||||
va_start(args,first_arg_name);
|
||||
gst_editor_element_construct(editorelement,parent,first_arg_name,args);
|
||||
va_end(args);
|
||||
|
||||
return editorelement;
|
||||
}
|
||||
|
||||
void gst_editor_element_construct(GstEditorElement *element,
|
||||
GstEditorBin *parent,
|
||||
const gchar *first_arg_name,
|
||||
va_list args) {
|
||||
GtkObject *obj = GTK_OBJECT(element);
|
||||
GSList *arg_list = NULL, *info_list = NULL;
|
||||
gchar *error;
|
||||
GstEditorElementClass *elementclass;
|
||||
|
||||
// g_print("in gst_editor_element_construct()\n");
|
||||
|
||||
error = gtk_object_args_collect(GTK_OBJECT_TYPE(obj),&arg_list,
|
||||
&info_list,first_arg_name,args);
|
||||
if (error) {
|
||||
g_warning("gst_editor_element_construct(): %s",error);
|
||||
g_free(error);
|
||||
} else {
|
||||
GSList *arg,*info;
|
||||
// g_print("setting all the arguments on the element\n");
|
||||
for (arg=arg_list,info=info_list;arg;arg=arg->next,info=info->next)
|
||||
gtk_object_arg_set(obj,arg->data,info->data);
|
||||
gtk_args_collect_cleanup(arg_list,info_list);
|
||||
}
|
||||
|
||||
if (parent)
|
||||
gst_editor_bin_add(parent,element);
|
||||
else if (!GST_IS_EDITOR_BIN(element))
|
||||
g_warning("floating element...\n");
|
||||
|
||||
elementclass = GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass);
|
||||
if (elementclass->realize)
|
||||
(elementclass->realize)(element);
|
||||
}
|
||||
|
||||
static void gst_editor_element_set_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditorElement *element;
|
||||
gdouble dx,dy,newwidth,newheight;
|
||||
|
||||
/* get the major types of this object */
|
||||
element = GST_EDITOR_ELEMENT(object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_X:
|
||||
element->x = GTK_VALUE_DOUBLE(*arg);
|
||||
break;
|
||||
case ARG_Y:
|
||||
element->y = GTK_VALUE_DOUBLE(*arg);
|
||||
break;
|
||||
case ARG_WIDTH:
|
||||
element->width = GTK_VALUE_DOUBLE(*arg);
|
||||
element->resize = TRUE;
|
||||
break;
|
||||
case ARG_HEIGHT:
|
||||
element->height = GTK_VALUE_DOUBLE(*arg);
|
||||
element->resize = TRUE;
|
||||
break;
|
||||
case ARG_X1:
|
||||
element->x = GTK_VALUE_DOUBLE(*arg);
|
||||
element->resize = TRUE;
|
||||
break;
|
||||
case ARG_Y1:
|
||||
element->y = GTK_VALUE_DOUBLE(*arg);
|
||||
element->resize = TRUE;
|
||||
break;
|
||||
case ARG_X2:
|
||||
// make sure it's big enough, grow if not
|
||||
element->width = MAX(GTK_VALUE_DOUBLE(*arg),element->minwidth);
|
||||
element->resize = TRUE;
|
||||
break;
|
||||
case ARG_Y2:
|
||||
// make sure it's big enough, grow if not
|
||||
element->height = MAX(GTK_VALUE_DOUBLE(*arg),element->minheight);
|
||||
element->resize = TRUE;
|
||||
break;
|
||||
default:
|
||||
g_warning("gsteditorelement: unknown arg!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_editor_element_get_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditorElement *element;
|
||||
|
||||
/* get the major types of this object */
|
||||
element = GST_EDITOR_ELEMENT(object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_X:
|
||||
GTK_VALUE_INT(*arg) = element->x + (element->width / 2.0);
|
||||
break;
|
||||
case ARG_Y:
|
||||
GTK_VALUE_INT(*arg) = element->y + (element->height / 2.0);
|
||||
break;
|
||||
case ARG_WIDTH:
|
||||
GTK_VALUE_INT(*arg) = element->width;
|
||||
break;
|
||||
case ARG_HEIGHT:
|
||||
GTK_VALUE_INT(*arg) = element->height;
|
||||
break;
|
||||
case ARG_X1:
|
||||
GTK_VALUE_INT(*arg) = element->x;
|
||||
break;
|
||||
case ARG_Y1:
|
||||
GTK_VALUE_INT(*arg) = element->y;
|
||||
break;
|
||||
case ARG_X2:
|
||||
GTK_VALUE_INT(*arg) = element->x + element->width;
|
||||
break;
|
||||
case ARG_Y2:
|
||||
GTK_VALUE_INT(*arg) = element->y + element->height;
|
||||
break;
|
||||
case ARG_ELEMENT:
|
||||
GTK_VALUE_POINTER(*arg) = element->element;
|
||||
break;
|
||||
default:
|
||||
arg->type = GTK_TYPE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_editor_element_realize(GstEditorElement *element) {
|
||||
GnomeCanvasGroup *parentgroup;
|
||||
gint i;
|
||||
gdouble x1,y1,x2,y2;
|
||||
GList *pads;
|
||||
GstPad *pad;
|
||||
|
||||
// g_print("realizing editor element %p\n",element);
|
||||
|
||||
/* we have to have a parent by this point */
|
||||
g_return_if_fail(element->parent != NULL);
|
||||
|
||||
// set the state signal of the actual element
|
||||
gtk_signal_connect(GTK_OBJECT(element->element),"state_change",
|
||||
GTK_SIGNAL_FUNC(gst_editor_element_state_change),
|
||||
element);
|
||||
|
||||
// create the bounds if we haven't had them set
|
||||
// g_print("centering element at %.2fx%.2f (%.2fx%.2f)\n",
|
||||
// element->x,element->y,element->width,element->height);
|
||||
|
||||
/* create the group holding all the stuff for this element */
|
||||
parentgroup = GST_EDITOR_ELEMENT(element->parent)->group;
|
||||
element->group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(parentgroup,
|
||||
gnome_canvas_group_get_type(),
|
||||
"x",element->x - (element->width / 2.0),
|
||||
"y",element->y - (element->height / 2.0),NULL));
|
||||
// g_print("origin of group is %.2fx%.2f\n",
|
||||
// element->x - (element->width / 2.0),
|
||||
// element->y - (element->height / 2.0));
|
||||
g_return_if_fail(element->group != NULL);
|
||||
GST_EDITOR_SET_OBJECT(element->group,element);
|
||||
gtk_signal_connect(GTK_OBJECT(element->group),"event",
|
||||
GTK_SIGNAL_FUNC(gst_editor_element_group_event),element);
|
||||
|
||||
// calculate the inter-group coords (x1,y1,x2,y2 are convenience vars)
|
||||
x1 = 0.0;y1 = 0.0;
|
||||
x2 = element->width;y2 = element->height;
|
||||
|
||||
/* create bordering box */
|
||||
element->border = gnome_canvas_item_new(element->group,
|
||||
gnome_canvas_rect_get_type(),
|
||||
"width_units",2.0,"fill_color","white","outline_color","black",
|
||||
"x1",x1,"y1",y1,"x2",x2,"y2",y2,NULL);
|
||||
g_return_if_fail(element->border != NULL);
|
||||
GST_EDITOR_SET_OBJECT(element->border,element);
|
||||
|
||||
/* create resizing box */
|
||||
element->resizebox = gnome_canvas_item_new(element->group,
|
||||
gnome_canvas_rect_get_type(),
|
||||
"width_units",1.0,"fill_color","white","outline_color","black",
|
||||
"x1",x2-4.0,"y1",y2-4.0,"x2",x2,"y2",y2,NULL);
|
||||
g_return_if_fail(element->resizebox != NULL);
|
||||
GST_EDITOR_SET_OBJECT(element->resizebox,element);
|
||||
gtk_signal_connect(GTK_OBJECT(element->resizebox),"event",
|
||||
GTK_SIGNAL_FUNC(gst_editor_element_resizebox_event),element);
|
||||
|
||||
/* create the title */
|
||||
element->title = gnome_canvas_item_new(element->group,
|
||||
gnome_canvas_text_get_type(),
|
||||
"text",gst_element_get_name(GST_OBJECT(element->element)),
|
||||
"x",x1+1.0,"y",y1+1.0,"anchor",GTK_ANCHOR_NORTH_WEST,
|
||||
"font_gdk",gtk_widget_get_default_style()->font,
|
||||
NULL);
|
||||
g_return_if_fail(element->title != NULL);
|
||||
GST_EDITOR_SET_OBJECT(element->title,element);
|
||||
|
||||
/* create the state boxen */
|
||||
for (i=0;i<4;i++) {
|
||||
element->statebox[i] = gnome_canvas_item_new(element->group,
|
||||
gnome_canvas_rect_get_type(),
|
||||
"width_units",1.0,"fill_color","white","outline_color","black",
|
||||
"x1",0.0,"y1",0.0,"x2",0.0,"y2",0.0,
|
||||
NULL);
|
||||
g_return_if_fail(element->statebox[i] != NULL);
|
||||
GST_EDITOR_SET_OBJECT(element->statebox[i],element);
|
||||
gtk_signal_connect(GTK_OBJECT(element->statebox[i]),"event",
|
||||
GTK_SIGNAL_FUNC(gst_editor_element_state_event),
|
||||
GINT_TO_POINTER(i));
|
||||
element->statetext[i] = gnome_canvas_item_new(element->group,
|
||||
gnome_canvas_text_get_type(),
|
||||
"text",_gst_editor_element_states[i],
|
||||
"x",0.0,"y",0.0,"anchor",GTK_ANCHOR_NORTH_WEST,
|
||||
"font","-*-*-*-*-*-*-6-*-*-*-*-*-*-*",
|
||||
NULL);
|
||||
g_return_if_fail(element->statetext[i] != NULL);
|
||||
GST_EDITOR_SET_OBJECT(element->statetext[i],element);
|
||||
gtk_signal_connect(GTK_OBJECT(element->statetext[i]),"event",
|
||||
GTK_SIGNAL_FUNC(gst_editor_element_state_event),
|
||||
GINT_TO_POINTER(i));
|
||||
}
|
||||
/* and the play box (FIXME: should be icons, not text */
|
||||
element->playbox = gnome_canvas_item_new(element->group,
|
||||
gnome_canvas_rect_get_type(),
|
||||
"width_units",1.0,"fill_color","white","outline_color","black",
|
||||
"x1",0.0,"y1",0.0,"x2",0.0,"y2",0.0,
|
||||
NULL);
|
||||
g_return_if_fail(element->playbox != NULL);
|
||||
GST_EDITOR_SET_OBJECT(element->playbox,element);
|
||||
gtk_signal_connect(GTK_OBJECT(element->playbox),"event",
|
||||
GTK_SIGNAL_FUNC(gst_editor_element_state_event),
|
||||
GINT_TO_POINTER(4));
|
||||
element->playtext = gnome_canvas_item_new(element->group,
|
||||
gnome_canvas_text_get_type(),
|
||||
"text","P",
|
||||
"x",0.0,"y",0.0,"anchor",GTK_ANCHOR_NORTH_WEST,
|
||||
"font","-*-*-*-*-*-*-6-*-*-*-*-*-*-*",
|
||||
NULL);
|
||||
g_return_if_fail(element->playtext != NULL);
|
||||
GST_EDITOR_SET_OBJECT(element->playtext,element);
|
||||
gtk_signal_connect(GTK_OBJECT(element->playtext),"event",
|
||||
GTK_SIGNAL_FUNC(gst_editor_element_state_event),
|
||||
GINT_TO_POINTER(4));
|
||||
|
||||
// get all the pads
|
||||
pads = gst_element_get_pad_list(element->element);
|
||||
while (pads) {
|
||||
pad = GST_PAD(pads->data);
|
||||
gst_editor_element_add_pad(element,pad);
|
||||
pads = g_list_next(pads);
|
||||
}
|
||||
|
||||
element->realized = TRUE;
|
||||
|
||||
// force a resize
|
||||
element->resize = TRUE;
|
||||
gst_editor_element_resize(element);
|
||||
|
||||
// recenter things on the supposed center
|
||||
// g_print("recentering element at %.2fx%.2f (%.2fx%.2f)\n",
|
||||
// element->x,element->y,element->width,element->height);
|
||||
element->x -= (element->width / 2.0);
|
||||
element->y -= (element->height / 2.0);
|
||||
gnome_canvas_item_set(GNOME_CANVAS_ITEM(element->group),
|
||||
"x",element->x,"y",element->y,NULL);
|
||||
// g_print("origin of group is %.2fx%.2f\n",element->x,element->y);
|
||||
|
||||
gst_editor_element_repack(element);
|
||||
}
|
||||
|
||||
|
||||
static void gst_editor_element_resize(GstEditorElement *element) {
|
||||
gdouble itemwidth,itemheight;
|
||||
gdouble groupwidth,groupheight;
|
||||
GList *pads;
|
||||
GstEditorPad *editorpad;
|
||||
gint i;
|
||||
|
||||
if (element->resize != TRUE) return;
|
||||
element->resize = FALSE;
|
||||
|
||||
// g_print("resizing element\n");
|
||||
|
||||
element->minwidth = element->insidewidth;
|
||||
element->minheight = element->insideheight;
|
||||
|
||||
// get the text size and add it into minsize
|
||||
g_return_if_fail(element->title != NULL);
|
||||
itemwidth = gst_util_get_double_arg(GTK_OBJECT(element->title),
|
||||
"text_width") + 2.0;
|
||||
itemheight = gst_util_get_double_arg(GTK_OBJECT(element->title),
|
||||
"text_height") + 2.0;
|
||||
element->titlewidth = itemwidth;
|
||||
element->titleheight = itemheight;
|
||||
element->minwidth = MAX(element->minwidth,itemwidth);
|
||||
element->minheight += itemheight;
|
||||
|
||||
// now do the bottom bar
|
||||
// find the biggest of the state chars
|
||||
element->statewidth = 0.0;element->stateheight = 0.0;
|
||||
for (i=0;i<4;i++) {
|
||||
g_return_if_fail(element->statetext[i] != NULL);
|
||||
itemwidth = gst_util_get_double_arg(GTK_OBJECT(element->statetext[i]),
|
||||
"text_width") - 2.0;
|
||||
itemwidth = gst_util_get_double_arg(GTK_OBJECT(element->statetext[i]),
|
||||
"text_height");
|
||||
element->statewidth = MAX(element->statewidth,itemwidth);
|
||||
element->stateheight = MAX(element->stateheight,itemheight);
|
||||
}
|
||||
// calculate the size of the primary group
|
||||
groupwidth = element->statewidth * 5; // 4 states plus playstate
|
||||
groupheight = element->stateheight;
|
||||
// add in the resize box
|
||||
groupwidth += 7.0; // 2.0 for buffer, 5.0 for actual size
|
||||
groupheight = MAX(groupheight,5.0);
|
||||
// update the minsize
|
||||
element->minwidth = MAX(element->minwidth,groupwidth);
|
||||
element->minheight += groupheight;
|
||||
|
||||
// now go and try to calculate necessary space for the pads
|
||||
element->sinkwidth = 10.0;element->sinkheight = 0.0;element->sinks = 0;
|
||||
pads = element->sinkpads;
|
||||
while (pads) {
|
||||
editorpad = GST_EDITOR_PAD(pads->data);
|
||||
element->sinkwidth = MAX(element->sinkwidth,editorpad->width);
|
||||
element->sinkheight = MAX(element->sinkheight,editorpad->height);
|
||||
element->sinks++;
|
||||
pads = g_list_next(pads);
|
||||
}
|
||||
element->srcwidth = 10.0;element->srcheight = 0.0;element->srcs = 0;
|
||||
pads = element->srcpads;
|
||||
while (pads) {
|
||||
editorpad = GST_EDITOR_PAD(pads->data);
|
||||
element->srcwidth = MAX(element->srcwidth,editorpad->width);
|
||||
element->srcheight = MAX(element->srcheight,editorpad->height);
|
||||
element->srcs++;
|
||||
pads = g_list_next(pads);
|
||||
}
|
||||
// add in the needed space
|
||||
element->minheight += MAX((element->sinkheight*element->sinks),
|
||||
(element->srcheight*element->srcs)) + 4.0;
|
||||
element->minwidth = MAX(element->minwidth,
|
||||
((element->sinkwidth*element->sinks) +
|
||||
(element->srcwidth*element->srcs) + 4.0));
|
||||
// g_print("have %d sinks (%.2fx%.2f) and %d srcs (%.2fx%.2f)\n",
|
||||
// element->sinks,element->sinkwidth,element->sinkheight,
|
||||
// element->srcs,element->srcwidth,element->srcheight);
|
||||
|
||||
// grow the element to hold all the stuff
|
||||
// g_print("minsize is %.2fx%.2f,
|
||||
//",element->minwidth,element->minheight);
|
||||
// g_print("size was %.2fx%.2f, ",element->width,element->height);
|
||||
element->width = MAX(element->width,element->minwidth);
|
||||
element->height = MAX(element->height,element->minheight);
|
||||
// g_print("is now %.2fx%.2f\n",element->width,element->height);
|
||||
}
|
||||
|
||||
void gst_editor_element_repack(GstEditorElement *element) {
|
||||
GList *pads;
|
||||
GstPad *pad;
|
||||
GstEditorPad *editorpad;
|
||||
gdouble sinkwidth,sinkheight;
|
||||
gint sinks;
|
||||
gdouble srcwidth,srcheight;
|
||||
gint srcs;
|
||||
gdouble x1,y1,x2,y2;
|
||||
gint i;
|
||||
|
||||
if (!element->realized) return;
|
||||
|
||||
gst_editor_element_resize(element);
|
||||
|
||||
// still use x1,y1,x2,y2 so we can change around later
|
||||
x1 = 0.0;y1 = 0.0;
|
||||
x2 = element->width;y2 = element->height;
|
||||
|
||||
// g_print("repacking element at %.2fx%.2f + %.2fx%.2f\n",
|
||||
// element->x,element->y,x2,y2);
|
||||
|
||||
// move the element group to match
|
||||
gnome_canvas_item_set(GNOME_CANVAS_ITEM(element->group),
|
||||
"x",element->x,"y",element->y,NULL);
|
||||
|
||||
// start by resizing the bordering box
|
||||
g_return_if_fail(element->border != NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->border),
|
||||
"x1",x1,"y1",y1,"x2",x2,"y2",y2,NULL);
|
||||
|
||||
// then move the text to the new top left
|
||||
g_return_if_fail(element->title != NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->title),
|
||||
"x",x1+1.0,"y",y1+1.0,
|
||||
"anchor",GTK_ANCHOR_NORTH_WEST,
|
||||
NULL);
|
||||
|
||||
// and move the resize box
|
||||
g_return_if_fail(element->resizebox != NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->resizebox),
|
||||
"x1",x2-5.0,"y1",y2-5.0,"x2",x2,"y2",y2,NULL);
|
||||
|
||||
// now place the state boxes
|
||||
for (i=0;i<4;i++) {
|
||||
g_return_if_fail(element->statebox[i] != NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->statebox[i]),
|
||||
"x1",x1+(element->statewidth*i),
|
||||
"y1",y2-element->stateheight,
|
||||
"x2",x1+(element->statewidth*(i+1)),"y2",y2,NULL);
|
||||
g_return_if_fail(element->statetext[i] != NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->statetext[i]),
|
||||
"x",x1+(element->statewidth*i)+2.0,
|
||||
"y",y2-element->stateheight+1.0,
|
||||
"anchor",GTK_ANCHOR_NORTH_WEST,NULL);
|
||||
}
|
||||
// and the playstate box
|
||||
g_return_if_fail(element->playbox != NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->playbox),
|
||||
"x1",x1+(element->statewidth*4),
|
||||
"y1",y2-element->stateheight,
|
||||
"x2",x1+(element->statewidth*5),"y2",y2,NULL);
|
||||
g_return_if_fail(element->playtext != NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->playtext),
|
||||
"x",x1+(element->statewidth*4)+2.0,
|
||||
"y",y2-element->stateheight+1.0,
|
||||
"anchor",GTK_ANCHOR_NORTH_WEST,NULL);
|
||||
|
||||
// now we try to place all the pads
|
||||
sinks = element->sinks;
|
||||
pads = element->sinkpads;
|
||||
while (pads) {
|
||||
editorpad = GST_EDITOR_PAD(pads->data);
|
||||
gtk_object_set(GTK_OBJECT(editorpad),
|
||||
"x",x1,
|
||||
"y",y2 - 2.0 - element->stateheight -
|
||||
(element->sinkheight * sinks),
|
||||
NULL);
|
||||
gst_editor_pad_repack(editorpad);
|
||||
sinks--;
|
||||
pads = g_list_next(pads);
|
||||
}
|
||||
|
||||
srcs = element->srcs;
|
||||
pads = element->srcpads;
|
||||
while (pads) {
|
||||
editorpad = GST_EDITOR_PAD(pads->data);
|
||||
gtk_object_set(GTK_OBJECT(editorpad),
|
||||
"x",x2 - element->srcwidth,
|
||||
"y",y2 - 2.0 - element->stateheight -
|
||||
(element->srcheight * srcs),
|
||||
NULL);
|
||||
gst_editor_pad_repack(editorpad);
|
||||
srcs--;
|
||||
pads = g_list_next(pads);
|
||||
}
|
||||
|
||||
// g_print("done resizing element\n");
|
||||
}
|
||||
|
||||
|
||||
GstEditorPad *gst_editor_element_add_pad(GstEditorElement *element,
|
||||
GstPad *pad) {
|
||||
GstEditorPad *editorpad;
|
||||
|
||||
editorpad = gst_editor_pad_new(element,pad,NULL);
|
||||
if (pad->direction == GST_PAD_SINK) {
|
||||
element->sinkpads = g_list_prepend(element->sinkpads,editorpad);
|
||||
element->sinks++;
|
||||
// g_print("added 'new' pad to sink list\n");
|
||||
} else if (pad->direction == GST_PAD_SRC) {
|
||||
element->srcpads = g_list_prepend(element->srcpads,editorpad);
|
||||
element->srcs++;
|
||||
// g_print("added 'new' pad to src list\n");
|
||||
} else
|
||||
g_print("HUH?!? Don't know which direction this pad is...\n");
|
||||
|
||||
element->padlistchange = TRUE;
|
||||
gst_editor_element_repack(element);
|
||||
return editorpad;
|
||||
}
|
||||
|
||||
|
||||
static gint gst_editor_element_group_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element) {
|
||||
// g_print("in group_event, type %d\n",event->type);
|
||||
if (GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass)->event)
|
||||
return (GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass)->event)(
|
||||
item,event,element);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static gint gst_editor_element_event(GnomeCanvasItem *item,GdkEvent *event,
|
||||
GstEditorElement *element) {
|
||||
gdouble item_x,item_y,dx,dy;
|
||||
GdkCursor *fleur;
|
||||
|
||||
// g_print("element in event, type %d\n",event->type);
|
||||
|
||||
switch(event->type) {
|
||||
case GDK_ENTER_NOTIFY:
|
||||
break;
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
break;
|
||||
case GDK_BUTTON_PRESS:
|
||||
// dragxy coords are world coords of button press
|
||||
element->dragx = event->button.x;
|
||||
element->dragy = event->button.y;
|
||||
// set some flags
|
||||
element->dragging = TRUE;
|
||||
element->moved = FALSE;
|
||||
fleur = gdk_cursor_new(GDK_FLEUR);
|
||||
gnome_canvas_item_grab(item,
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
// GDK_ENTER_NOTIFY_MASK |
|
||||
// GDK_LEAVE_NOTIFY_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK,
|
||||
fleur,event->button.time);
|
||||
return TRUE;
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if (element->dragging) {
|
||||
dx = event->button.x - element->dragx;
|
||||
dy = event->button.y - element->dragy;
|
||||
gst_editor_element_move(element,dx,dy);
|
||||
element->dragx = event->button.x;
|
||||
element->dragy = event->button.y;
|
||||
element->moved = TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
break;
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (element->dragging) {
|
||||
element->dragging = FALSE;
|
||||
gnome_canvas_item_ungrab(item,event->button.time);
|
||||
}
|
||||
if (!element->moved) {
|
||||
GstEditorElementClass *elementclass;
|
||||
elementclass = GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass);
|
||||
if (elementclass->button_event)
|
||||
(elementclass->button_event)(item,event,element);
|
||||
}
|
||||
//g_print("in element group_event, setting inchild");
|
||||
element->canvas->inchild = TRUE;
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static gint gst_editor_element_resizebox_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorElement *element) {
|
||||
GdkCursor *bottomright;
|
||||
gdouble item_x,item_y;
|
||||
|
||||
// g_print("in resizebox_event...\n");
|
||||
|
||||
// calculate coords relative to the group, not the box
|
||||
item_x = event->button.x;
|
||||
item_y = event->button.y;
|
||||
gnome_canvas_item_w2i(item->parent,&item_x,&item_y);
|
||||
|
||||
switch(event->type) {
|
||||
case GDK_ENTER_NOTIFY:
|
||||
break;
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
element->hesitating = FALSE;
|
||||
break;
|
||||
case GDK_BUTTON_PRESS:
|
||||
element->dragx = event->button.x;
|
||||
element->dragy = event->button.y;
|
||||
element->resizing = TRUE;
|
||||
element->hesitating = TRUE;
|
||||
bottomright = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER);
|
||||
gnome_canvas_item_grab(item,
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_ENTER_NOTIFY_MASK |
|
||||
GDK_LEAVE_NOTIFY_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK,
|
||||
bottomright,event->button.time);
|
||||
return TRUE;
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if (element->resizing) {
|
||||
// doing a set because the code is in the arg set code
|
||||
// g_print("resizing to x2,y2 of %.2f,%.2f\n",item_x,item_y);
|
||||
gtk_object_set(GTK_OBJECT(element),"x2",item_x,"y2",item_y,NULL);
|
||||
element->resize = TRUE;
|
||||
gst_editor_element_repack(element);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (element->resizing) {
|
||||
element->resizing = FALSE;
|
||||
gnome_canvas_item_ungrab(item,event->button.time);
|
||||
//g_print("in element resizebox_event, setting inchild");
|
||||
element->canvas->inchild = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static gint gst_editor_element_state_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
gpointer data) {
|
||||
GstEditorElement *element;
|
||||
gint id = GPOINTER_TO_INT(data);
|
||||
GdkCursor *uparrow;
|
||||
|
||||
element = GST_EDTIOR_GET_OBJECT(item);
|
||||
|
||||
switch (event->type) {
|
||||
case GDK_ENTER_NOTIFY:
|
||||
uparrow = gdk_cursor_new(GDK_SB_UP_ARROW);
|
||||
gnome_canvas_item_grab(item,
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_LEAVE_NOTIFY_MASK,
|
||||
uparrow,event->button.time);
|
||||
/* NOTE: when grabbing canvas item, always get pointer_motion,
|
||||
this will allow you to actually get all the other synth events */
|
||||
break;
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
gnome_canvas_item_ungrab(item,event->button.time);
|
||||
break;
|
||||
case GDK_BUTTON_PRESS:
|
||||
return TRUE;
|
||||
break;
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (id < 5) {
|
||||
element->states[id] = !element->states[id];
|
||||
gst_editor_element_set_state(element,id,TRUE);
|
||||
} else
|
||||
g_warning("Uh, shouldn't have gotten here, unknown state\n");
|
||||
//g_print("in element statebox_event, setting inchild");
|
||||
element->canvas->inchild = TRUE;
|
||||
return TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void gst_editor_element_set_state(GstEditorElement *element,
|
||||
gint id,gboolean set) {
|
||||
gboolean stateset = TRUE; /* if we have no element, set anyway */
|
||||
if (element->states[id]) {
|
||||
/* set the object state */
|
||||
if (set && element->element)
|
||||
stateset = gst_element_set_state(element->element,(1 << id));
|
||||
/* change the display */
|
||||
if (stateset) {
|
||||
if (id < 4) {
|
||||
gtk_object_set(GTK_OBJECT(element->statebox[id]),
|
||||
"fill_color","black",NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->statetext[id]),
|
||||
"fill_color","white",NULL);
|
||||
} else if (id == 4) {
|
||||
gtk_object_set(GTK_OBJECT(element->playbox),
|
||||
"fill_color","black",NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->playtext),
|
||||
"fill_color","white",NULL);
|
||||
}
|
||||
} else {
|
||||
g_print("error setting state %d\n",id);
|
||||
element->states[id] = !element->states[id];
|
||||
}
|
||||
} else {
|
||||
if (set && element->element)
|
||||
stateset = gst_element_set_state(element->element,~(1 << id));
|
||||
if (stateset) {
|
||||
if (id < 4) {
|
||||
gtk_object_set(GTK_OBJECT(element->statebox[id]),
|
||||
"fill_color","white",NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->statetext[id]),
|
||||
"fill_color","black",NULL);
|
||||
} else if (id == 4) {
|
||||
gtk_object_set(GTK_OBJECT(element->playbox),
|
||||
"fill_color","white",NULL);
|
||||
gtk_object_set(GTK_OBJECT(element->playtext),
|
||||
"fill_color","black",NULL);
|
||||
}
|
||||
} else {
|
||||
g_print("error unsetting state %d\n",id);
|
||||
element->states[id] = !element->states[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gst_editor_element_state_change(GstElement *element,
|
||||
gint state,
|
||||
GstEditorElement *editorelement) {
|
||||
gint id;
|
||||
|
||||
g_return_if_fail(editorelement != NULL);
|
||||
|
||||
// g_print("gst_editor_element_state_change got state 0x%08x\n",state);
|
||||
// if it's an unset
|
||||
if (state & GST_STATE_MAX) {
|
||||
state = ~state;
|
||||
for (id=0;id<(sizeof(state)*8)-1;id++) {
|
||||
if (state & 1) {
|
||||
editorelement->states[id] = FALSE;
|
||||
break;
|
||||
}
|
||||
state /= 2;
|
||||
}
|
||||
} else {
|
||||
for (id=0;id<(sizeof(state)*8)-1;id++) {
|
||||
if (state & 1) {
|
||||
editorelement->states[id] = TRUE;
|
||||
break;
|
||||
}
|
||||
state /= 2;
|
||||
}
|
||||
}
|
||||
gst_editor_element_set_state(editorelement,id,FALSE);
|
||||
}
|
||||
|
||||
static void gst_editor_element_sync_state(GstEditorElement *element) {
|
||||
gint id;
|
||||
|
||||
// g_print("syncronizing state\n");
|
||||
for (id=0;id<5;id++) {
|
||||
element->states[id] = GST_FLAG_IS_SET(element->element,1<<id);
|
||||
gst_editor_element_set_state(element,id,FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_editor_element_move(GstEditorElement *element,
|
||||
gdouble dx,gdouble dy) {
|
||||
GList *pads;
|
||||
GstEditorPad *pad;
|
||||
|
||||
// this is a 'little' trick to keep from repacking the whole thing...
|
||||
element->x += dx;element->y += dy;
|
||||
gnome_canvas_item_move(GNOME_CANVAS_ITEM(element->group),dx,dy);
|
||||
|
||||
pads = element->srcpads;
|
||||
while (pads) {
|
||||
pad = GST_EDITOR_PAD(pads->data);
|
||||
if (pad->connection) {
|
||||
// g_print("updating pad's connection\n");
|
||||
pad->connection->resize = TRUE;
|
||||
gst_editor_connection_resize(pad->connection);
|
||||
}
|
||||
pads = g_list_next(pads);
|
||||
}
|
||||
pads = element->sinkpads;
|
||||
while (pads) {
|
||||
pad = GST_EDITOR_PAD(pads->data);
|
||||
if (pad->connection) {
|
||||
// g_print("updating pad's connection\n");
|
||||
pad->connection->resize = TRUE;
|
||||
gst_editor_connection_resize(pad->connection);
|
||||
}
|
||||
pads = g_list_next(pads);
|
||||
}
|
||||
}
|
406
editor/gsteditorpad.c
Normal file
406
editor/gsteditorpad.c
Normal file
|
@ -0,0 +1,406 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <gnome.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gsteditor.h"
|
||||
|
||||
/* class functions */
|
||||
static void gst_editor_pad_class_init(GstEditorPadClass *klass);
|
||||
static void gst_editor_pad_init(GstEditorPad *pad);
|
||||
static void gst_editor_pad_set_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_pad_get_arg(GtkObject *object,GtkArg *arg,guint id);
|
||||
static void gst_editor_pad_realize(GstEditorPad *pad);
|
||||
|
||||
/* class implementation functions */
|
||||
static void gst_editor_pad_update(GnomeCanvasItem *item,double *affine,
|
||||
ArtSVP *clip_path,int flags);
|
||||
static gint gst_editor_pad_event(GnomeCanvasItem *item,GdkEvent *event);
|
||||
|
||||
/* events fired by items within self */
|
||||
static gint gst_editor_pad_padbox_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorPad *pad);
|
||||
|
||||
/* utility functions */
|
||||
static void gst_editor_pad_resize(GstEditorPad *pad);
|
||||
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_X,
|
||||
ARG_Y,
|
||||
ARG_WIDTH,
|
||||
ARG_HEIGHT,
|
||||
ARG_PAD,
|
||||
};
|
||||
|
||||
enum {
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static GtkObjectClass *parent_class;
|
||||
static guint gst_editor_pad_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
GtkType gst_editor_pad_get_type() {
|
||||
static GtkType pad_type = 0;
|
||||
|
||||
if (!pad_type) {
|
||||
static const GtkTypeInfo pad_info = {
|
||||
"GstEditorPad",
|
||||
sizeof(GstEditorPad),
|
||||
sizeof(GstEditorPadClass),
|
||||
(GtkClassInitFunc)gst_editor_pad_class_init,
|
||||
(GtkObjectInitFunc)gst_editor_pad_init,
|
||||
NULL,
|
||||
NULL,
|
||||
(GtkClassInitFunc)NULL,
|
||||
};
|
||||
pad_type = gtk_type_unique(gtk_object_get_type(),&pad_info);
|
||||
}
|
||||
return pad_type;
|
||||
}
|
||||
|
||||
static void gst_editor_pad_class_init(GstEditorPadClass *klass) {
|
||||
GtkObjectClass *object_class;
|
||||
|
||||
object_class = (GtkObjectClass*)klass;
|
||||
|
||||
parent_class = gtk_type_class(gtk_object_get_type());
|
||||
|
||||
gtk_object_add_arg_type("GstEditorPad::x",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_X);
|
||||
gtk_object_add_arg_type("GstEditorPad::y",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_Y);
|
||||
gtk_object_add_arg_type("GstEditorPad::width",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_WIDTH);
|
||||
gtk_object_add_arg_type("GstEditorPad::height",GTK_TYPE_DOUBLE,
|
||||
GTK_ARG_READWRITE,ARG_HEIGHT);
|
||||
gtk_object_add_arg_type("GstEditorPad::pad",GTK_TYPE_POINTER,
|
||||
GTK_ARG_READWRITE,ARG_PAD);
|
||||
|
||||
klass->realize = gst_editor_pad_realize;
|
||||
|
||||
object_class->set_arg = gst_editor_pad_set_arg;
|
||||
object_class->get_arg = gst_editor_pad_get_arg;
|
||||
}
|
||||
|
||||
static void gst_editor_pad_init(GstEditorPad *pad) {
|
||||
}
|
||||
|
||||
GstEditorPad *gst_editor_pad_new(GstEditorElement *parent,GstPad *pad,
|
||||
const gchar *first_arg_name, ...) {
|
||||
GstEditorPad *editorpad;
|
||||
va_list args;
|
||||
|
||||
g_return_if_fail(parent != NULL);
|
||||
g_return_if_fail(GST_IS_EDITOR_ELEMENT(parent));
|
||||
g_return_if_fail(pad != NULL);
|
||||
g_return_if_fail(GST_IS_PAD(pad));
|
||||
|
||||
editorpad = GST_EDITOR_PAD(gtk_type_new(GST_TYPE_EDITOR_PAD));
|
||||
editorpad->pad = pad;
|
||||
|
||||
va_start(args,first_arg_name);
|
||||
gst_editor_pad_construct(editorpad,parent,first_arg_name,args);
|
||||
va_end(args);
|
||||
|
||||
return editorpad;
|
||||
}
|
||||
|
||||
void gst_editor_pad_construct(GstEditorPad *pad,
|
||||
GstEditorElement *parent,
|
||||
const gchar *first_arg_name,va_list args) {
|
||||
GtkObject *obj = GTK_OBJECT(pad);
|
||||
GSList *arg_list = NULL, *info_list = NULL;
|
||||
gchar *error;
|
||||
GstEditorPadClass *padclass;
|
||||
|
||||
// g_print("in gst_editor_pad_construct()\n");
|
||||
|
||||
error = gtk_object_args_collect(GTK_OBJECT_TYPE(obj),&arg_list,
|
||||
&info_list,first_arg_name,args);
|
||||
if (error) {
|
||||
g_warning("gst_editor_pad_construct(): %s",error);
|
||||
g_free(error);
|
||||
} else {
|
||||
GSList *arg,*info;
|
||||
// g_print("setting all the arguments on the pad\n");
|
||||
for (arg=arg_list,info=info_list;arg;arg=arg->next,info=info->next)
|
||||
gtk_object_arg_set(obj,arg->data,info->data);
|
||||
gtk_args_collect_cleanup(arg_list,info_list);
|
||||
}
|
||||
|
||||
pad->parent = parent;
|
||||
|
||||
padclass = GST_EDITOR_PAD_CLASS(GTK_OBJECT(pad)->klass);
|
||||
if (padclass)
|
||||
(padclass->realize)(pad);
|
||||
}
|
||||
|
||||
static void gst_editor_pad_set_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditorPad *pad;
|
||||
|
||||
/* get the major types of this object */
|
||||
pad = GST_EDITOR_PAD(object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_X:
|
||||
pad->x = GTK_VALUE_DOUBLE(*arg);
|
||||
break;
|
||||
case ARG_Y:
|
||||
pad->y = GTK_VALUE_DOUBLE(*arg);
|
||||
break;
|
||||
case ARG_WIDTH:
|
||||
pad->width = GTK_VALUE_DOUBLE(*arg);
|
||||
pad->resize = TRUE;
|
||||
break;
|
||||
case ARG_HEIGHT:
|
||||
pad->height = GTK_VALUE_DOUBLE(*arg);
|
||||
pad->resize = TRUE;
|
||||
break;
|
||||
case ARG_PAD:
|
||||
/* FIXME: this is very brute force */
|
||||
pad->pad = GTK_VALUE_POINTER(*arg);
|
||||
break;
|
||||
default:
|
||||
g_warning("gsteditorpad: unknown arg!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_editor_pad_get_arg(GtkObject *object,GtkArg *arg,guint id) {
|
||||
GstEditorPad *pad;
|
||||
|
||||
/* get the major types of this object */
|
||||
pad = GST_EDITOR_PAD(object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_X:
|
||||
GTK_VALUE_INT(*arg) = pad->x;
|
||||
break;
|
||||
case ARG_Y:
|
||||
GTK_VALUE_INT(*arg) = pad->y;
|
||||
break;
|
||||
case ARG_WIDTH:
|
||||
GTK_VALUE_INT(*arg) = pad->width;
|
||||
break;
|
||||
case ARG_HEIGHT:
|
||||
GTK_VALUE_INT(*arg) = pad->height;
|
||||
break;
|
||||
default:
|
||||
arg->type = GTK_TYPE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_editor_pad_realize(GstEditorPad *pad) {
|
||||
gint i;
|
||||
|
||||
// g_print("realizing editor pad %p\n",pad);
|
||||
|
||||
/* we must be attached to an element */
|
||||
g_return_if_fail(pad->parent != NULL);
|
||||
|
||||
/* create the group and bounding box */
|
||||
pad->group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(pad->parent->group,
|
||||
gnome_canvas_group_get_type(),"x",pad->x,"y",pad->y,NULL));
|
||||
g_return_if_fail(pad->group != NULL);
|
||||
GST_EDITOR_SET_OBJECT(pad->group,pad);
|
||||
|
||||
pad->border = gnome_canvas_item_new(pad->group,
|
||||
gnome_canvas_rect_get_type(),
|
||||
"width_units",1.0,"fill_color","white","outline_color","black",
|
||||
"x1",0.0,"y1",0.0,"x2",pad->width,"y2",pad->height,NULL);
|
||||
g_return_if_fail(pad->border != NULL);
|
||||
GST_EDITOR_SET_OBJECT(pad->border,pad);
|
||||
|
||||
/* create the pad box on the correct side */
|
||||
pad->issrc = (pad->pad->direction == GST_PAD_SRC);
|
||||
if (pad->issrc)
|
||||
pad->padbox = gnome_canvas_item_new(pad->group,
|
||||
gnome_canvas_rect_get_type(),
|
||||
"width_units",1.0,"fill_color","white","outline_color","black",
|
||||
"x1",pad->x-4.0,"y1",2.0,"x2",pad->x,"y2",pad->height-2.0,NULL);
|
||||
else
|
||||
pad->padbox = gnome_canvas_item_new(pad->group,
|
||||
gnome_canvas_rect_get_type(),
|
||||
"width_units",1.0,"fill_color","white","outline_color","black",
|
||||
"x1",0.0,"y1",2.0,"x2",4.0,"y2",pad->height-2.0,NULL);
|
||||
g_return_if_fail(pad->padbox != NULL);
|
||||
GST_EDITOR_SET_OBJECT(pad->padbox,pad);
|
||||
gtk_signal_connect(GTK_OBJECT(pad->padbox),"event",
|
||||
GTK_SIGNAL_FUNC(gst_editor_pad_padbox_event),pad);
|
||||
|
||||
pad->title = gnome_canvas_item_new(pad->group,
|
||||
gnome_canvas_text_get_type(),
|
||||
"text",gst_pad_get_name(pad->pad),
|
||||
"x",0.0,"y",0.0,"anchor",GTK_ANCHOR_NORTH_WEST,
|
||||
"font_gdk",gtk_widget_get_default_style()->font,
|
||||
NULL);
|
||||
g_return_if_fail(pad->title != NULL);
|
||||
GST_EDITOR_SET_OBJECT(pad->title,pad);
|
||||
|
||||
pad->realized = TRUE;
|
||||
pad->resize = TRUE;
|
||||
gst_editor_pad_repack(pad);
|
||||
}
|
||||
|
||||
|
||||
static void gst_editor_pad_resize(GstEditorPad *pad) {
|
||||
gdouble minwidth,minheight;
|
||||
|
||||
// g_print("resizing pad\n");
|
||||
|
||||
minwidth = 0;minheight = 0;
|
||||
|
||||
/* get the text size and add it into minsize */
|
||||
minwidth = gst_util_get_double_arg(GTK_OBJECT(pad->title),
|
||||
"text_width") + 2.0;
|
||||
minheight = gst_util_get_double_arg(GTK_OBJECT(pad->title),
|
||||
"text_height");
|
||||
|
||||
/* calculate the size of the padbox */
|
||||
pad->boxheight = minheight - 4.0;
|
||||
pad->boxwidth = pad->boxheight / 2.0;
|
||||
minwidth += pad->boxwidth;
|
||||
|
||||
/* force the thing to grow if necessary */
|
||||
pad->width = MAX(pad->width,minwidth);
|
||||
pad->height = MAX(pad->height,minheight);
|
||||
|
||||
/* update the connection if there is one */
|
||||
// g_print("connection is %p\n",pad->connection);
|
||||
if (pad->connection != NULL)
|
||||
gst_editor_connection_resize(pad->connection);
|
||||
}
|
||||
|
||||
void gst_editor_pad_repack(GstEditorPad *pad) {
|
||||
gdouble x1,y1,x2,y2;
|
||||
|
||||
if (!pad->realized) return;
|
||||
|
||||
gst_editor_pad_resize(pad);
|
||||
|
||||
x1 = 0;y1 = 0;
|
||||
x2 = x1 + pad->width;y2 = y1 + pad->height;
|
||||
// g_print("repacking pad at %.2fx%.2f - %.2fx%.2f\n",x1,y1,x2,y2);
|
||||
|
||||
/* move the group */
|
||||
gtk_object_set(GTK_OBJECT(pad->group),"x",pad->x,"y",pad->y,NULL);
|
||||
|
||||
/* start by resizing the bordering box */
|
||||
gtk_object_set(GTK_OBJECT(pad->border),
|
||||
"x1",x1,"y1",y1,"x2",x2,"y2",y2,NULL);
|
||||
|
||||
/* if we're a left-jusified sink */
|
||||
if (pad->issrc) {
|
||||
/* and move the pad box */
|
||||
gtk_object_set(GTK_OBJECT(pad->padbox),
|
||||
"x1",x2-pad->boxwidth,"y1",y1+2.0,
|
||||
"x2",x2,"y2",y2-2.0,NULL);
|
||||
/* then move the text to the right place */
|
||||
gtk_object_set(GTK_OBJECT(pad->title),
|
||||
"x",x2-pad->boxwidth-1.0,"y",y1,
|
||||
"anchor",GTK_ANCHOR_NORTH_EAST,
|
||||
NULL);
|
||||
} else {
|
||||
/* and move the pad box */
|
||||
gtk_object_set(GTK_OBJECT(pad->padbox),
|
||||
"x1",x1,"y1",y1+2.0,
|
||||
"x2",x1+pad->boxwidth,"y2",y2-2.0,NULL);
|
||||
/* then move the text to the right place */
|
||||
gtk_object_set(GTK_OBJECT(pad->title),
|
||||
"x",x1+pad->boxwidth+1.0,"y",y1,
|
||||
"anchor",GTK_ANCHOR_NORTH_WEST,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (pad->connection != NULL) {
|
||||
pad->connection->resize = TRUE;
|
||||
gst_editor_connection_resize(pad->connection);
|
||||
}
|
||||
|
||||
pad->resize = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
static gint gst_editor_pad_event(GnomeCanvasItem *item,GdkEvent *event) {
|
||||
GstEditorPad *pad = GST_EDITOR_PAD(item);
|
||||
gdouble item_x,item_y;
|
||||
GdkCursor *fleur;
|
||||
gdouble tx,ty;
|
||||
|
||||
item_x = event->button.x;
|
||||
item_y = event->button.y;
|
||||
gnome_canvas_item_w2i(item->parent,&item_x,&item_y);
|
||||
|
||||
switch(event->type) {
|
||||
case GDK_ENTER_NOTIFY:
|
||||
// g_print("entered pad\n");
|
||||
break;
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
// g_print("left pad\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
*/
|
||||
|
||||
/* FIXME FIXME FIXME */
|
||||
static gint gst_editor_pad_padbox_event(GnomeCanvasItem *item,
|
||||
GdkEvent *event,
|
||||
GstEditorPad *pad) {
|
||||
GstEditorElement *element;
|
||||
GstEditorBin *bin;
|
||||
|
||||
// g_print("padbox has event %d\n",event->type);
|
||||
g_return_if_fail(GST_IS_EDITOR_PAD(pad));
|
||||
|
||||
element = pad->parent;
|
||||
bin = element->parent;
|
||||
|
||||
switch(event->type) {
|
||||
case GDK_ENTER_NOTIFY:
|
||||
// g_print("entered pad '%s'\n",
|
||||
// gst_pad_get_name(pad->pad));
|
||||
break;
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
// g_print("left pad '%s'\n",
|
||||
// gst_pad_get_name(pad->pad));
|
||||
break;
|
||||
case GDK_BUTTON_PRESS:
|
||||
// g_print("have button press in pad '%s'\n",
|
||||
// gst_pad_get_name(pad->pad));
|
||||
gst_editor_bin_start_banding(bin,pad);
|
||||
return TRUE;
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
// g_print("have motion in pad\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
79
editor/gsteditorpad.h
Normal file
79
editor/gsteditorpad.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_EDITOR_PAD_H__
|
||||
#define __GST_EDITOR_PAD_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#define GST_TYPE_EDITOR_PAD \
|
||||
(gst_editor_pad_get_type())
|
||||
#define GST_EDITOR_PAD(obj) \
|
||||
(GTK_CHECK_CAST((obj),GST_TYPE_EDITOR_PAD,GstEditorPad))
|
||||
#define GST_EDITOR_PAD_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EDITOR_PAD,GstEditorPad))
|
||||
#define GST_IS_EDITOR_PAD(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_EDITOR_PAD))
|
||||
#define GST_IS_EDITOR_PAD_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EDITOR_PAD)))
|
||||
|
||||
typedef struct _GstEditorPad GstEditorPad;
|
||||
typedef struct _GstEditorPadClass GstEditorPadClass;
|
||||
|
||||
struct _GstEditorPad {
|
||||
GtkObject object;
|
||||
|
||||
/* parent object */
|
||||
GtkObject *parent; // FIXME!!!
|
||||
|
||||
/* the pad we're associated with */
|
||||
GstPad *pad;
|
||||
gboolean issink;
|
||||
|
||||
/* visual stuff */
|
||||
GnomeCanvasGroup *group;
|
||||
GnomeCanvasItem *border,*title,*padbox;
|
||||
gboolean sinkpad; // is this a sink pad?
|
||||
gdouble x,y; // location
|
||||
gdouble width,height; // actual size
|
||||
gdouble boxwidth,boxheight; // size of pad box
|
||||
gboolean resize; // does it need resizing?
|
||||
|
||||
/* interaction state */
|
||||
gboolean dragging,resizing,moved;
|
||||
gdouble dragx,dragy;
|
||||
|
||||
/* connection */
|
||||
// GnomeCanvasItem *connection; // can't use
|
||||
//GstEditorConnection
|
||||
};
|
||||
|
||||
struct _GstEditorPadClass {
|
||||
GtkObjectClass parent_class;
|
||||
};
|
||||
|
||||
GtkType gst_editor_pad_get_type();
|
||||
GstEditorPad *gst_editor_pad_new(GstEditorElement *parent,GstPad *pad,
|
||||
const gchar *first_arg_name, ...);
|
||||
void gst_editor_pad_construct(GstEditorPad *element,
|
||||
GstEditorElement *parent,
|
||||
const gchar *first_arg_name,va_list args);
|
||||
|
||||
#endif /* __GST_EDITOR_PAD_H__ */
|
278
editor/gstelementselect.c
Normal file
278
editor/gstelementselect.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gnome.h>
|
||||
|
||||
struct element_select_classlist {
|
||||
gchar *name;
|
||||
GSList *subclasses;
|
||||
GSList *factories;
|
||||
};
|
||||
|
||||
struct element_select_details {
|
||||
GstElementFactory *factory;
|
||||
GtkWidget *longname, *description, *version, *author, *copyright;
|
||||
};
|
||||
|
||||
static gint compare_name(gconstpointer a,gconstpointer b) {
|
||||
return (strcmp(((GstElementFactory *)a)->name,
|
||||
((GstElementFactory *)b)->name));
|
||||
}
|
||||
|
||||
gint str_compare(gconstpointer a,gconstpointer b) {
|
||||
return (strcmp((gchar *)a,(gchar *)b));
|
||||
}
|
||||
|
||||
/* this function creates a GtkCTreeNode with the contents of the classtree */
|
||||
static void make_ctree(GtkCTree *tree,GtkCTreeNode *parent,
|
||||
struct element_select_classlist *class) {
|
||||
GSList *traverse;
|
||||
GtkCTreeNode *classnode, *node = NULL;
|
||||
gchar *data[2];
|
||||
|
||||
data[0] = g_strdup(class->name);
|
||||
data[1] = NULL;
|
||||
classnode = gtk_ctree_insert_node(tree,parent,NULL,data,0,
|
||||
NULL,NULL,NULL,NULL,FALSE,TRUE);
|
||||
gtk_ctree_node_set_selectable(tree,classnode,FALSE);
|
||||
|
||||
traverse = class->subclasses;
|
||||
while (traverse) {
|
||||
make_ctree(tree,classnode,
|
||||
(struct element_select_classlist *)(traverse->data));
|
||||
traverse = g_slist_next(traverse);
|
||||
}
|
||||
|
||||
traverse = class->factories;
|
||||
while (traverse) {
|
||||
GstElementFactory *factory = (GstElementFactory *)(traverse->data);
|
||||
data[0] = g_strdup(factory->name);
|
||||
data[1] = g_strdup(factory->details->description);
|
||||
node = gtk_ctree_insert_node(tree,classnode,NULL,data,0,
|
||||
NULL,NULL,NULL,NULL,TRUE,FALSE);
|
||||
gtk_ctree_node_set_row_data_full(tree,node,factory,NULL);
|
||||
traverse = g_slist_next(traverse);
|
||||
}
|
||||
}
|
||||
|
||||
static void ctree_select(GtkWidget *widget,gint row,gint column,
|
||||
GdkEventButton *bevent,gpointer data) {
|
||||
GtkCTree *tree = GTK_CTREE(widget);
|
||||
GtkCTreeNode *node;
|
||||
GstElementFactory *factory;
|
||||
struct element_select_details *details;
|
||||
node = gtk_ctree_node_nth(tree,row);
|
||||
factory = (GstElementFactory *)gtk_ctree_node_get_row_data(tree,node);
|
||||
if (!factory)
|
||||
return;
|
||||
details = (struct element_select_details *)data;
|
||||
details->factory = factory;
|
||||
|
||||
gtk_entry_set_text(GTK_ENTRY(details->longname),
|
||||
factory->details->longname);
|
||||
gtk_entry_set_text(GTK_ENTRY(details->description),
|
||||
factory->details->description);
|
||||
gtk_entry_set_text(GTK_ENTRY(details->version),
|
||||
factory->details->version);
|
||||
gtk_entry_set_text(GTK_ENTRY(details->author),
|
||||
factory->details->author);
|
||||
gtk_entry_set_text(GTK_ENTRY(details->copyright),
|
||||
factory->details->copyright);
|
||||
|
||||
if (bevent && bevent->type == GDK_2BUTTON_PRESS)
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
|
||||
GstElementFactory *element_select_dialog() {
|
||||
GtkWidget *dialog;
|
||||
gchar *titles[2];
|
||||
GtkWidget *ctree;
|
||||
GtkWidget *scroller;
|
||||
GtkTable *table;
|
||||
GtkWidget *detailslabel;
|
||||
GtkWidget *detailshsep;
|
||||
GtkWidget *longname, *description, *version, *author, *copyright;
|
||||
|
||||
GList *elements;
|
||||
GstElementFactory *element;
|
||||
gchar **classes, **class;
|
||||
GSList *classlist;
|
||||
GSList *classtree, *treewalk;
|
||||
GSList **curlist;
|
||||
struct element_select_classlist *branch;
|
||||
struct element_select_details details;
|
||||
|
||||
/* first create the dialog and associated stuff */
|
||||
dialog = gnome_dialog_new("Select Element",
|
||||
GNOME_STOCK_BUTTON_OK,
|
||||
GNOME_STOCK_BUTTON_CANCEL,
|
||||
NULL);
|
||||
gnome_dialog_set_close(GNOME_DIALOG(dialog),TRUE);
|
||||
gnome_dialog_close_hides(GNOME_DIALOG(dialog),TRUE);
|
||||
gnome_dialog_set_default(GNOME_DIALOG(dialog),GNOME_OK);
|
||||
|
||||
titles[0] = "Element ";
|
||||
titles[1] = "Description";
|
||||
ctree = gtk_ctree_new_with_titles(2,0,titles);
|
||||
gtk_widget_set_usize(ctree,400,350);
|
||||
|
||||
scroller = gtk_scrolled_window_new(NULL,NULL);
|
||||
gtk_container_add(GTK_CONTAINER(scroller),ctree);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
|
||||
GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
|
||||
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),scroller,
|
||||
TRUE,TRUE,0);
|
||||
|
||||
/* create the details table and put a title on it */
|
||||
table = GTK_TABLE(gtk_table_new(2,7,FALSE));
|
||||
detailslabel = gtk_label_new("Element Details:");
|
||||
gtk_misc_set_alignment(GTK_MISC(detailslabel),0.0,0.5);
|
||||
gtk_table_attach(table,detailslabel,0,2,0,1,GTK_FILL|GTK_EXPAND,0,0,0);
|
||||
|
||||
/* then a separator to keep the title separate */
|
||||
detailshsep = gtk_hseparator_new();
|
||||
gtk_table_attach(table,detailshsep,0,2,1,2,GTK_FILL|GTK_EXPAND,0,0,0);
|
||||
|
||||
/* the long name of the element */
|
||||
longname = gtk_label_new("Name:");
|
||||
gtk_misc_set_alignment(GTK_MISC(longname),1.0,0.5);
|
||||
gtk_table_attach(table,longname,0,1,2,3,GTK_FILL,0,5,0);
|
||||
details.longname = gtk_entry_new();
|
||||
gtk_entry_set_editable(GTK_ENTRY(details.longname),FALSE);
|
||||
gtk_table_attach(table,details.longname,1,2,2,3,GTK_FILL|GTK_EXPAND,0,0,0);
|
||||
|
||||
/* the description */
|
||||
description = gtk_label_new("Description:");
|
||||
gtk_misc_set_alignment(GTK_MISC(description),1.0,0.5);
|
||||
gtk_table_attach(table,description,0,1,3,4,GTK_FILL,0,5,0);
|
||||
details.description = gtk_entry_new();
|
||||
gtk_entry_set_editable(GTK_ENTRY(details.description),FALSE);
|
||||
gtk_table_attach(table,details.description,1,2,3,4,GTK_FILL|GTK_EXPAND,0,0,0);
|
||||
|
||||
/* the version */
|
||||
version = gtk_label_new("Version:");
|
||||
gtk_misc_set_alignment(GTK_MISC(version),1.0,0.5);
|
||||
gtk_table_attach(table,version,0,1,4,5,GTK_FILL,0,5,0);
|
||||
details.version = gtk_entry_new();
|
||||
gtk_entry_set_editable(GTK_ENTRY(details.version),FALSE);
|
||||
gtk_table_attach(table,details.version,1,2,4,5,GTK_FILL|GTK_EXPAND,0,0,0);
|
||||
|
||||
/* the author */
|
||||
author = gtk_label_new("Author:");
|
||||
gtk_misc_set_alignment(GTK_MISC(author),1.0,0.5);
|
||||
gtk_table_attach(table,author,0,1,6,7,GTK_FILL,0,5,0);
|
||||
details.author = gtk_entry_new();
|
||||
gtk_entry_set_editable(GTK_ENTRY(details.author),FALSE);
|
||||
gtk_table_attach(table,details.author,1,2,6,7,GTK_FILL|GTK_EXPAND,0,0,0);
|
||||
|
||||
/* the copyright */
|
||||
copyright = gtk_label_new("Copyright:");
|
||||
gtk_misc_set_alignment(GTK_MISC(copyright),1.0,0.5);
|
||||
gtk_table_attach(table,copyright,0,1,7,8,GTK_FILL,0,5,0);
|
||||
details.copyright = gtk_entry_new();
|
||||
gtk_entry_set_editable(GTK_ENTRY(details.copyright),FALSE);
|
||||
gtk_table_attach(table,details.copyright,1,2,7,8,GTK_FILL|GTK_EXPAND,0,0,0);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),GTK_WIDGET(table),
|
||||
TRUE,TRUE,0);
|
||||
|
||||
|
||||
/* first create a sorted (by class) tree of all the factories */
|
||||
classtree = NULL;
|
||||
elements = gst_elementfactory_get_list();
|
||||
while (elements) {
|
||||
element = (GstElementFactory *)(elements->data);
|
||||
/* split up the factory's class */
|
||||
classes = g_strsplit(element->details->class,"/",0);
|
||||
class = classes;
|
||||
curlist = &classtree;
|
||||
/* walk down the class tree to find where to place this element */
|
||||
/* the goal is for treewalk to point to the right class branch */
|
||||
/* when we exit this thing, branch is pointing where we want */
|
||||
while (*class) {
|
||||
treewalk = *curlist;
|
||||
/* walk the current level of class to see if we have the class */
|
||||
while (treewalk) {
|
||||
branch = (struct element_select_classlist *)(treewalk->data);
|
||||
/* see if this class matches what we're looking for */
|
||||
if (!strcmp(branch->name,*class)) {
|
||||
/* if so, we progress down the list into this one's list */
|
||||
curlist = &branch->subclasses;
|
||||
break;
|
||||
}
|
||||
treewalk = g_slist_next(treewalk);
|
||||
}
|
||||
/* if treewalk == NULL, it wasn't in the list. add one */
|
||||
if (treewalk == NULL) {
|
||||
/* curlist is pointer to list */
|
||||
branch = g_new0(struct element_select_classlist,1);
|
||||
branch->name = g_strdup(*class);
|
||||
*curlist = g_slist_insert_sorted(*curlist,branch,str_compare);
|
||||
curlist = &branch->subclasses;
|
||||
}
|
||||
class++;
|
||||
}
|
||||
/* theoretically branch points where we want now */
|
||||
branch->factories = g_slist_insert_sorted(branch->factories,element,
|
||||
compare_name);
|
||||
elements = g_list_next(elements);
|
||||
}
|
||||
|
||||
/* now fill in the ... */
|
||||
gtk_clist_freeze(GTK_CLIST(ctree));
|
||||
treewalk = classtree;
|
||||
while (treewalk) {
|
||||
make_ctree(GTK_CTREE(ctree),NULL,
|
||||
(struct element_select_classlist *)(treewalk->data));
|
||||
treewalk = g_slist_next(treewalk);
|
||||
}
|
||||
gtk_clist_thaw(GTK_CLIST(ctree));
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(ctree),"select_row",
|
||||
GTK_SIGNAL_FUNC(ctree_select),&details);
|
||||
|
||||
gtk_widget_show_all(GTK_WIDGET(dialog));
|
||||
|
||||
details.factory = NULL;
|
||||
if (gnome_dialog_run_and_close(GNOME_DIALOG(dialog)) == GNOME_CANCEL)
|
||||
return NULL;
|
||||
else
|
||||
return details.factory;
|
||||
};
|
||||
|
||||
|
||||
/* this is available so we can do a quick test of this thing */
|
||||
#ifdef ELEMENTSELECT_MAIN
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElementFactory *chosen;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
gnome_init("elementselect_test","0.0.0",argc,argv);
|
||||
chosen = element_select_dialog();
|
||||
if (chosen)
|
||||
g_print("selected '%s'\n",chosen->name);
|
||||
else
|
||||
g_print("didn't choose any\n");
|
||||
exit(0);
|
||||
}
|
||||
#endif /* ELEMENTSELECT_MAIN */
|
23
editor/gstelementselect.h
Normal file
23
editor/gstelementselect.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
GstElementFactory *element_select_dialog();
|
5
gst/xml/Makefile.am
Normal file
5
gst/xml/Makefile.am
Normal file
|
@ -0,0 +1,5 @@
|
|||
bin_PROGRAMS = save
|
||||
|
||||
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) $(XML_CFLAGS) -I$(top_srcdir)
|
||||
LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(XML_LIBS) $(top_srcdir)/gst/libgst.la
|
||||
|
6
gst/xml/notes
Normal file
6
gst/xml/notes
Normal file
|
@ -0,0 +1,6 @@
|
|||
The naming hiearchy you'll see bits of but never the whole thing is
|
||||
basically container:container:container:element.pad, which reflects
|
||||
parentage. When naming connections between elements, those are the what
|
||||
will be used, possibly along with .. as container to indicate 'up one'. I
|
||||
don't think this will ever by used, since ghost pads are supposed to make
|
||||
all connections between elements with the same parent.
|
43
gst/xml/save.c
Normal file
43
gst/xml/save.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
GstPipeline *create_pipeline() {
|
||||
GstPipeline *pipeline;
|
||||
GstElement *src, *sink;
|
||||
GstPad *srcpad, *sinkpad;
|
||||
|
||||
pipeline = gst_pipeline_new("fake_pipeline");
|
||||
g_return_if_fail(pipeline != NULL);
|
||||
|
||||
src = gst_elementfactory_make("fakesrc","fakesrc");
|
||||
g_return_if_fail(src != NULL);
|
||||
sink = gst_elementfactory_make("fakesink","fakesink");
|
||||
g_return_if_fail(sink != NULL);
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(sink));
|
||||
|
||||
srcpad = gst_element_get_pad(src,"src");
|
||||
g_return_if_fail(srcpad != NULL);
|
||||
sinkpad = gst_element_get_pad(sink,"sink");
|
||||
g_return_if_fail(srcpad != NULL);
|
||||
|
||||
gst_pad_connect(srcpad,sinkpad);
|
||||
|
||||
return GST_PIPELINE(pipeline);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *pipeline;
|
||||
xmlDocPtr doc;
|
||||
|
||||
// _gst_plugin_spew = TRUE;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
pipeline = GST_ELEMENT(create_pipeline());
|
||||
|
||||
doc = gst_xml_write(pipeline);
|
||||
xmlSaveFile("save.xml",doc);
|
||||
}
|
21
test/Makefile.am
Normal file
21
test/Makefile.am
Normal file
|
@ -0,0 +1,21 @@
|
|||
#bin_PROGRAMS = basic m types a r plugin w s args mpg123 mcut push qtest
|
||||
bin_PROGRAMS = qtest spectrum record wave mp3 teardown buffer mp3parse \
|
||||
mpeg2parse mp3play ac3parse ac3play dvdcat fake cobin
|
||||
|
||||
SUBDIRS = xml cothreads
|
||||
|
||||
spectrum_CFLAGS = $(shell gnome-config --cflags gnomeui)
|
||||
spectrum_LDFLAGS = $(shell gnome-config --libs gnomeui)
|
||||
wave_CFLAGS = $(shell gnome-config --cflags gnomeui)
|
||||
wave_LDFLAGS = $(shell gnome-config --libs gnomeui)
|
||||
|
||||
buffer_SOURCES = buffer.c mem.c
|
||||
teardown_SOURCES = teardown.c mem.c
|
||||
ac3play_SOURCES = ac3play.c mem.c
|
||||
|
||||
LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la
|
||||
|
||||
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) -I$(top_srcdir) \
|
||||
$(shell gnome-config --cflags gnomeui)
|
||||
|
||||
EXTRA_DIST = README
|
69
test/a.c
Normal file
69
test/a.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
g_print("have eof, quitting\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstType *autype;
|
||||
GList *factories;
|
||||
GstElementFactory *parsefactory;
|
||||
GstElement *bin, *disksrc, *parse, *audiosink;
|
||||
GList *padlist;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
disksrc = gst_disksrc_new("disksrc");
|
||||
g_print("created disksrc\n");
|
||||
if (argc == 2)
|
||||
gst_disksrc_set_filename(disksrc,argv[1]);
|
||||
else
|
||||
gst_disksrc_set_filename(disksrc,"Thank_you_very_much.au");
|
||||
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
|
||||
|
||||
|
||||
/* now it's time to get the parser */
|
||||
autype = gst_type_get_by_mime("audio/au");
|
||||
factories = gst_type_get_sinks(autype);
|
||||
if (factories != NULL)
|
||||
parsefactory = GST_ELEMENTFACTORY(factories->data);
|
||||
else {
|
||||
g_print("sorry, can't find anyone registered to sink 'au'\n");
|
||||
return 1;
|
||||
}
|
||||
parse = gst_elementfactory_create(parsefactory,"parser");
|
||||
if (parse == NULL) {
|
||||
g_print("sorry, couldn't create parser\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
audiosink = gst_audiosink_new("audiosink");
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
gst_element_get_pad(audiosink,"sink"));
|
||||
|
||||
while(1)
|
||||
gst_disksrc_push(GST_SRC(disksrc));
|
||||
|
||||
gst_object_destroy(GST_OBJECT(audiosink));
|
||||
gst_object_destroy(GST_OBJECT(parse));
|
||||
gst_object_destroy(GST_OBJECT(disksrc));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
55
test/ac3parse.c
Normal file
55
test/ac3parse.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
void ac3parse_info_chain(GstPad *pad,GstBuffer *buf) {
|
||||
g_print("got buffer of size %d\n",GST_BUFFER_SIZE(buf));
|
||||
gst_buffer_unref(buf);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstPipeline *pipeline;
|
||||
GstElementFactory *srcfactory, *parsefactory;
|
||||
GstElement *src, *parse;
|
||||
GstPad *infopad;
|
||||
|
||||
g_print("have %d args\n",argc);
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
// gst_plugin_load("ac3parse");
|
||||
gst_plugin_load_all();
|
||||
|
||||
pipeline = gst_pipeline_new("pipeline");
|
||||
g_return_if_fail(pipeline != NULL);
|
||||
|
||||
srcfactory = gst_elementfactory_find("disksrc");
|
||||
g_return_if_fail(srcfactory != NULL);
|
||||
parsefactory = gst_elementfactory_find("ac3parse");
|
||||
g_return_if_fail(parsefactory != NULL);
|
||||
|
||||
src = gst_elementfactory_create(srcfactory,"src");
|
||||
g_return_if_fail(src != NULL);
|
||||
gtk_object_set(GTK_OBJECT(src),"location",argv[1],"bytesperread",4096,NULL);
|
||||
g_print("should be using file '%s'\n",argv[1]);
|
||||
parse = gst_elementfactory_create(parsefactory,"parse");
|
||||
g_return_if_fail(parse != NULL);
|
||||
|
||||
infopad = gst_pad_new("sink",GST_PAD_SINK);
|
||||
gst_pad_set_chain_function(infopad,ac3parse_info_chain);
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
infopad);
|
||||
|
||||
g_print("setting to RUNNING state\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
|
||||
|
||||
g_print("about to enter loop\n");
|
||||
while (1)
|
||||
gst_src_push(GST_SRC(src));
|
||||
}
|
84
test/ac3play.c
Normal file
84
test/ac3play.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *pipeline, *decodethread, *playthread;
|
||||
GstElement *src, *parse, *decode, *play;
|
||||
GstElement *queue;
|
||||
GstPad *infopad;
|
||||
|
||||
g_print("have %d args\n",argc);
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
// gst_plugin_load("ac3parse");
|
||||
gst_plugin_load_all();
|
||||
|
||||
pipeline = gst_elementfactory_make("pipeline","ac3player");
|
||||
g_return_if_fail(pipeline != NULL);
|
||||
decodethread = gst_elementfactory_make("thread","decodethread");
|
||||
g_return_if_fail(decodethread != NULL);
|
||||
playthread = gst_elementfactory_make("thread","playthread");
|
||||
g_return_if_fail(playthread != NULL);
|
||||
queue = gst_elementfactory_make("queue","queue");
|
||||
g_return_if_fail(queue != NULL);
|
||||
|
||||
src = gst_elementfactory_make("disksrc","src");
|
||||
g_return_if_fail(src != NULL);
|
||||
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
|
||||
g_print("should be using file '%s'\n",argv[1]);
|
||||
parse = gst_elementfactory_make("ac3parse","parse");
|
||||
g_return_if_fail(parse != NULL);
|
||||
decode = gst_elementfactory_make("ac3dec","decode");
|
||||
g_return_if_fail(decode != NULL);
|
||||
play = gst_elementfactory_make("audiosink","play");
|
||||
g_return_if_fail(play != NULL);
|
||||
|
||||
// construct the decode thread
|
||||
g_print("constructing the decode thread\n");
|
||||
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(parse));
|
||||
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(decode));
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
gst_element_get_pad(decode,"sink"));
|
||||
gst_element_add_ghost_pad(GST_ELEMENT(decodethread),
|
||||
gst_element_get_pad(decode,"src"));
|
||||
|
||||
// construct the play thread
|
||||
g_print("constructing the play thread\n");
|
||||
gst_bin_add(GST_BIN(playthread),GST_ELEMENT(play));
|
||||
gst_element_add_ghost_pad(GST_ELEMENT(playthread),
|
||||
gst_element_get_pad(play,"sink"));
|
||||
|
||||
// construct the outer pipeline
|
||||
g_print("constructing the main pipeline\n");
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(decodethread));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(queue));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(playthread));
|
||||
gst_pad_connect(gst_element_get_pad(decodethread,"src"),
|
||||
gst_element_get_pad(queue,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(queue,"src"),
|
||||
gst_element_get_pad(playthread,"sink"));
|
||||
|
||||
// set thread start state
|
||||
gtk_object_set(GTK_OBJECT(decodethread),"create_thread",TRUE,NULL);
|
||||
gtk_object_set(GTK_OBJECT(playthread),"create_thread",FALSE,NULL);
|
||||
|
||||
g_print("setting to RUNNING state\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
|
||||
|
||||
// sleep(1);
|
||||
g_print("about to enter loop\n");
|
||||
while (1) {
|
||||
gst_thread_iterate(GST_THREAD(playthread));
|
||||
g_print("using %d bytes\n",vmsize());
|
||||
}
|
||||
|
||||
xmlSaveFile("ac3play.xml",gst_xml_write(GST_ELEMENT(pipeline)));
|
||||
}
|
24
test/ac3sync.c
Normal file
24
test/ac3sync.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
int fd;
|
||||
int offset = 0;
|
||||
int got;
|
||||
unsigned short buf[2048];
|
||||
int i;
|
||||
int prev = 0;
|
||||
|
||||
if (argc >= 2) fd = open(argv[1],O_RDONLY);
|
||||
else fd = 0;
|
||||
|
||||
while (got = read(fd,buf,sizeof(buf))) {
|
||||
for (i=0;i<(got/2);i++) {
|
||||
if (buf[i] == 0x770b) {
|
||||
printf("have sync at %d (+%d)\n",offset+(i*2),(offset+(i*2))-prev);
|
||||
prev = offset+(i*2);
|
||||
}
|
||||
}
|
||||
offset += got;
|
||||
}
|
||||
}
|
20
test/args.c
Normal file
20
test/args.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *src;
|
||||
GList *padlist;
|
||||
GtkArg arg;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
src = gst_disksrc_new("fakesrc");
|
||||
gtk_object_set(GTK_OBJECT(src),"location","demo.mp3",NULL);
|
||||
|
||||
arg.name = "location";
|
||||
gtk_object_getv(GTK_OBJECT(src),1,&arg);
|
||||
g_print("location is %s\n",GTK_VALUE_STRING(arg));
|
||||
|
||||
gst_object_destroy(GST_OBJECT(src));
|
||||
}
|
||||
|
109
test/basic.c
Normal file
109
test/basic.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
void added_child(GstObject *object,GstObject *child) {
|
||||
g_print("added_child(): added child '%s' to '%s'\n",
|
||||
gst_object_get_name(child),
|
||||
gst_object_get_name(object));
|
||||
}
|
||||
|
||||
void added_parent(GstObject *object,GstObject *parent) {
|
||||
g_print("added_parent(): object '%s' has new parent '%s'\n",
|
||||
gst_object_get_name(object),
|
||||
gst_object_get_name(parent));
|
||||
}
|
||||
|
||||
void list_pads(GstElement *element) {
|
||||
GList *padlist;
|
||||
|
||||
padlist = gst_element_get_pad_list(element);
|
||||
if (padlist == NULL)
|
||||
g_print("%s has no pads...\n",gst_object_get_name(element));
|
||||
else {
|
||||
while (padlist) {
|
||||
GstPad *pad = GST_PAD(padlist->data);
|
||||
if (gst_pad_get_ghost_parent(pad) == GST_OBJECT(element))
|
||||
g_print("'%s' had %s ghost pad '%s'\n",gst_object_get_name(element),
|
||||
(gst_pad_get_direction(pad) == GST_PAD_SRC) ? "SRC" : "SINK",
|
||||
gst_pad_get_name(pad));
|
||||
else
|
||||
g_print("'%s' had %s pad '%s'\n",gst_object_get_name(element),
|
||||
(gst_pad_get_direction(pad) == GST_PAD_SRC) ? "SRC" : "SINK",
|
||||
gst_pad_get_name(pad));
|
||||
padlist = g_list_next(padlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *bin, *src, *binf, *filter1, *filter2, *sink;
|
||||
GList *padlist;
|
||||
|
||||
gtk_init(&argc,&argv);
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
src = gst_disksrc_new("fakesrc");
|
||||
gst_disksrc_set_filename(src,"demo.mp3");
|
||||
list_pads(src);
|
||||
|
||||
binf = gst_bin_new("binf");
|
||||
|
||||
filter1 = gst_fakefilter_new("filter1");
|
||||
list_pads(filter1);
|
||||
|
||||
filter2 = gst_fakefilter_new("filter2");
|
||||
list_pads(filter2);
|
||||
|
||||
sink = gst_fakesink_new("fakesink");
|
||||
list_pads(sink);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(bin),"object_added",
|
||||
GTK_SIGNAL_FUNC(added_child),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(binf),"object_added",
|
||||
GTK_SIGNAL_FUNC(added_child),NULL);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(binf),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(src),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(filter1),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(filter2),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(sink),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
|
||||
/* add filter1 to the subbin */
|
||||
gst_bin_add(GST_BIN(binf),GST_ELEMENT(filter1));
|
||||
gst_bin_add(GST_BIN(binf),GST_ELEMENT(filter2));
|
||||
/* connect the two together */
|
||||
gst_pad_connect(gst_element_get_pad(filter1,"src"),
|
||||
gst_element_get_pad(filter2,"sink"));
|
||||
/* export the pads */
|
||||
gst_element_add_ghost_pad(binf,gst_element_get_pad(filter1,"sink"));
|
||||
gst_element_add_ghost_pad(binf,gst_element_get_pad(filter2,"src"));
|
||||
list_pads(binf);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(src));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(binf));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(sink));
|
||||
|
||||
/* connect src to binf */
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(binf,"sink"));
|
||||
/* connect binf to sink */
|
||||
gst_pad_connect(gst_element_get_pad(binf,"src"),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
gst_disksrc_push(GST_SRC(src));
|
||||
|
||||
gst_object_destroy(GST_OBJECT(src));
|
||||
gst_object_destroy(GST_OBJECT(filter1));
|
||||
gst_object_destroy(GST_OBJECT(filter2));
|
||||
gst_object_destroy(GST_OBJECT(binf));
|
||||
gst_object_destroy(GST_OBJECT(sink));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
11
test/bindings/Makefile.am
Normal file
11
test/bindings/Makefile.am
Normal file
|
@ -0,0 +1,11 @@
|
|||
lib_LTLIBRARIES = libcrashtest.la
|
||||
|
||||
libcrashtest_la_SOURCES = \
|
||||
dummy.c
|
||||
|
||||
include_HEADERS = \
|
||||
dummy.h
|
||||
|
||||
bin_PROGRAMS = test
|
||||
|
||||
test_LDADD = libcrashtest.la
|
20
test/bindings/dummy.c
Normal file
20
test/bindings/dummy.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <dummy.h>
|
||||
|
||||
Dummy *dummy_new() {
|
||||
Dummy *dummy;
|
||||
|
||||
dummy = g_malloc(sizeof(Dummy));
|
||||
|
||||
dummy->flags = 0;
|
||||
dummy->name = NULL;
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
Dummy *dummy_new_with_name(gchar *name) {
|
||||
Dummy *dummy = dummy_new();
|
||||
|
||||
dummy->name = g_strdup(name);
|
||||
|
||||
return dummy;
|
||||
}
|
19
test/bindings/dummy.h
Normal file
19
test/bindings/dummy.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef __DUMMY_H__
|
||||
#define __DUMMY_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define DUMMY(dummy) ((Dummy *)(dummy))
|
||||
|
||||
typedef struct _Dummy Dummy;
|
||||
|
||||
struct _Dummy {
|
||||
gint flags;
|
||||
|
||||
gchar *name;
|
||||
};
|
||||
|
||||
Dummy *dummy_new();
|
||||
Dummy *dummy_new_with_name(gchar *name);
|
||||
|
||||
#endif /* __DUMMY_H__ */
|
11
test/bindings/test.c
Normal file
11
test/bindings/test.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <glib.h>
|
||||
#include <dummy.h>
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
Dummy *driver,*passenger;
|
||||
|
||||
driver = dummy_new();
|
||||
passenger = dummy_new_with_name("moron");
|
||||
|
||||
g_print("created a couple of dummies, %p and %p\n",driver,passenger);
|
||||
}
|
53
test/buffer.c
Normal file
53
test/buffer.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstBuffer *buf;
|
||||
GstBuffer **buffers;
|
||||
gpointer dummy;
|
||||
int i,max;
|
||||
long usage1,usage2;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
max = atoi(argv[1]);
|
||||
|
||||
g_print("creating and destroying a buffer %d times...",max);
|
||||
usage1 = vmsize();
|
||||
for (i=0;i<max;i++) {
|
||||
buf = gst_buffer_new();
|
||||
gst_buffer_unref(buf);
|
||||
}
|
||||
usage2 = vmsize();
|
||||
g_print(" used %d more bytes\n",usage2-usage1);
|
||||
|
||||
// g_print("pre-allocating space...");
|
||||
// usage1 = vmsize();
|
||||
// dummy = g_malloc(100*i);
|
||||
// usage2 = vmsize();
|
||||
// g_print(" (+%d)\n",usage2-usage1);
|
||||
|
||||
g_print("creating %d buffers...",max);
|
||||
buffers = g_new(GstBuffer,i);
|
||||
usage1 = vmsize();
|
||||
for (i=0;i<max;i++)
|
||||
buffers[i] = gst_buffer_new();
|
||||
// buffers[i] = (GstBuffer *)g_malloc(1024);
|
||||
usage2 = vmsize();
|
||||
g_print(" (+%d bytes), and destroying them...",usage2-usage1);
|
||||
usage1 = vmsize();
|
||||
for (i=0;i<max;i++)
|
||||
gst_buffer_unref(buffers[i]);
|
||||
// g_free(buffers[i]);
|
||||
usage2 = vmsize();
|
||||
g_print("(-%d)\n",usage1-usage2);
|
||||
g_free(buffers);
|
||||
|
||||
g_print("buffer is %d bytes, list is %d bytes\n",
|
||||
sizeof(GstBuffer),sizeof(GList));
|
||||
|
||||
g_print("memory usage is %d\n",vmsize());
|
||||
}
|
42
test/cobin.c
Normal file
42
test/cobin.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *bin;
|
||||
GstElement *src, *identity, *sink;
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
bin = gst_elementfactory_make("bin","bin");
|
||||
g_return_if_fail(bin != NULL);
|
||||
|
||||
g_print("--- creating src and sink elements\n");
|
||||
src = gst_elementfactory_make("fakesrc","src");
|
||||
g_return_if_fail(src != NULL);
|
||||
identity = gst_elementfactory_make(argv[1],"identity");
|
||||
g_return_if_fail(identity != NULL);
|
||||
sink = gst_elementfactory_make("fakesink","sink");
|
||||
g_return_if_fail(sink != NULL);
|
||||
|
||||
g_print("--- about to add the elements to the pipeline\n");
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(identity));
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(sink));
|
||||
|
||||
g_print("--- connecting\n");
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(identity,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(identity,"src"),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
g_print("--- creating a plan\n");
|
||||
gst_bin_create_plan(GST_BIN(bin));
|
||||
|
||||
g_print("--- starting up\n");
|
||||
gst_bin_iterate(GST_BIN(bin));
|
||||
|
||||
g_print("\n");
|
||||
}
|
5
test/cothreads/Makefile.am
Normal file
5
test/cothreads/Makefile.am
Normal file
|
@ -0,0 +1,5 @@
|
|||
bin_PROGRAMS = test simple
|
||||
|
||||
test_SOURCES = test.c cothreads.c object.c looper.c
|
||||
|
||||
simple_SOURCES = simple.c cothreads.c
|
143
test/cothreads/cothreads.c
Normal file
143
test/cothreads/cothreads.c
Normal file
|
@ -0,0 +1,143 @@
|
|||
#include <sys/time.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "cothreads.h"
|
||||
|
||||
pthread_key_t _cothread_key = -1;
|
||||
|
||||
cothread_state *cothread_create(cothread_context *ctx) {
|
||||
cothread_state *s;
|
||||
|
||||
if (pthread_self() == 0) {
|
||||
s = (cothread_state *)malloc(sizeof(int) * COTHREAD_STACKSIZE);
|
||||
} else {
|
||||
char *sp = CURRENT_STACK_FRAME;
|
||||
unsigned long *stack_end = (unsigned long *)((unsigned long)sp &
|
||||
~(STACK_SIZE - 1));
|
||||
s = (cothread_state *)(stack_end + ((ctx->nthreads - 1) *
|
||||
COTHREAD_STACKSIZE));
|
||||
if (mmap((char *)s,COTHREAD_STACKSIZE*(sizeof(int)),
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE|MAP_ANONYMOUS,
|
||||
-1,0) < 0) {
|
||||
perror("mmap'ing cothread stack space");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
s->ctx = ctx;
|
||||
s->threadnum = ctx->nthreads;
|
||||
s->flags = 0;
|
||||
s->sp = (int *)(s + COTHREAD_STACKSIZE);
|
||||
|
||||
ctx->threads[ctx->nthreads++] = s;
|
||||
|
||||
// printf("created cothread at %p\n",s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void cothread_setfunc(cothread_state *thread,cothread_func func,int argc,char **argv) {
|
||||
thread->func = func;
|
||||
thread->argc = argc;
|
||||
thread->argv = argv;
|
||||
thread->pc = (int *)func;
|
||||
}
|
||||
|
||||
cothread_context *cothread_init() {
|
||||
cothread_context *ctx = (cothread_context *)malloc(sizeof(cothread_context));
|
||||
|
||||
if (_cothread_key == -1) {
|
||||
if (pthread_key_create(&_cothread_key,NULL) != 0) {
|
||||
perror("pthread_key_create");
|
||||
return;
|
||||
}
|
||||
}
|
||||
pthread_setspecific(_cothread_key,ctx);
|
||||
|
||||
memset(ctx->threads,0,sizeof(ctx->threads));
|
||||
|
||||
ctx->threads[0] = (cothread_state *)malloc(sizeof(cothread_state));
|
||||
ctx->threads[0]->ctx = ctx;
|
||||
ctx->threads[0]->threadnum = 0;
|
||||
ctx->threads[0]->func = NULL;
|
||||
ctx->threads[0]->argc = 0;
|
||||
ctx->threads[0]->argv = NULL;
|
||||
ctx->threads[0]->flags = COTHREAD_STARTED;
|
||||
ctx->threads[0]->sp = CURRENT_STACK_FRAME;
|
||||
ctx->threads[0]->pc = 0;
|
||||
|
||||
// fprintf(stderr,"0th thread is at %p\n",ctx->threads[0]);
|
||||
|
||||
// we consider the initiating process to be cothread 0
|
||||
ctx->nthreads = 1;
|
||||
ctx->current = 0;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
cothread_state *cothread_main(cothread_context *ctx) {
|
||||
// fprintf(stderr,"returning %p, the 0th cothread\n",ctx->threads[0]);
|
||||
return ctx->threads[0];
|
||||
}
|
||||
|
||||
void cothread_stub() {
|
||||
cothread_context *ctx = pthread_getspecific(_cothread_key);
|
||||
register cothread_state *thread = ctx->threads[ctx->current];
|
||||
|
||||
thread->flags |= COTHREAD_STARTED;
|
||||
thread->func(thread->argc,thread->argv);
|
||||
thread->flags &= ~COTHREAD_STARTED;
|
||||
thread->pc = 0;
|
||||
// printf("uh, yeah, we shouldn't be here, but we should deal anyway\n");
|
||||
}
|
||||
|
||||
void cothread_switch(cothread_state *thread) {
|
||||
cothread_context *ctx;
|
||||
cothread_state *current;
|
||||
int enter = 0;
|
||||
// int i;
|
||||
|
||||
if (thread == NULL)
|
||||
return;
|
||||
|
||||
ctx = thread->ctx;
|
||||
|
||||
current = ctx->threads[ctx->current];
|
||||
if (current == NULL) {
|
||||
fprintf(stderr,"there's no current thread, help!\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (current == thread) {
|
||||
fprintf(stderr,"trying to switch to same thread, legal but not necessary\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// find the number of the thread to switch to
|
||||
ctx->current = thread->threadnum;
|
||||
// fprintf(stderr,"about to switch to thread #%d\n",ctx->current);
|
||||
|
||||
/* save the current stack pointer, frame pointer, and pc */
|
||||
__asm__("movl %%esp, %0" : "=m"(current->sp) : : "esp", "ebp");
|
||||
enter = setjmp(current->jmp);
|
||||
if (enter != 0)
|
||||
return;
|
||||
enter = 1;
|
||||
|
||||
/* restore stack pointer and other stuff of new cothread */
|
||||
__asm__("movl %0, %%esp\n" : "=m"(thread->sp));
|
||||
if (thread->flags & COTHREAD_STARTED) {
|
||||
// switch to it
|
||||
longjmp(thread->jmp,1);
|
||||
} else {
|
||||
// start it
|
||||
__asm__("jmp " SYMBOL_NAME_STR(cothread_stub));
|
||||
}
|
||||
}
|
48
test/cothreads/cothreads.h
Normal file
48
test/cothreads/cothreads.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef __COTHREADS_H__
|
||||
#define __COTHREADS_H__
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define COTHREAD_STACKSIZE 8192
|
||||
#define COTHREAD_MAXTHREADS 16
|
||||
#define STACK_SIZE 0x200000
|
||||
|
||||
#ifndef CURRENT_STACK_FRAME
|
||||
#define CURRENT_STACK_FRAME ({ char __csf; &__csf; })
|
||||
#endif /* CURRENT_STACK_FRAME */
|
||||
|
||||
typedef struct _cothread_state cothread_state;
|
||||
typedef struct _cothread_context cothread_context;
|
||||
|
||||
typedef int (*cothread_func)(int argc,char **argv);
|
||||
|
||||
#define COTHREAD_STARTED 0x01
|
||||
|
||||
struct _cothread_state {
|
||||
cothread_context *ctx;
|
||||
int threadnum;
|
||||
|
||||
cothread_func func;
|
||||
int argc;
|
||||
char **argv;
|
||||
|
||||
int flags;
|
||||
int *sp;
|
||||
int *pc;
|
||||
jmp_buf jmp;
|
||||
};
|
||||
|
||||
struct _cothread_context {
|
||||
cothread_state *threads[COTHREAD_MAXTHREADS];
|
||||
int nthreads;
|
||||
int current;
|
||||
};
|
||||
|
||||
cothread_context *cothread_init();
|
||||
cothread_state *cothread_create(cothread_context *ctx);
|
||||
void cothread_setfunc(cothread_state *thread,cothread_func func,int argc,char **argv);
|
||||
void cothread_switch(cothread_state *thread);
|
||||
cothread_state *cothread_main(cothread_context *ctx);
|
||||
|
||||
#endif /* __COTHREAD_H__ */
|
47
test/cothreads/looper.c
Normal file
47
test/cothreads/looper.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include <stdio.h>
|
||||
#include "looper.h"
|
||||
|
||||
void looper_loopfunc(object *obj);
|
||||
|
||||
void looper_init(looper *l,int source) {
|
||||
l->source = source;
|
||||
object_setloopfunc(OBJECT(l),looper_loopfunc);
|
||||
}
|
||||
|
||||
looper *looper_create(char *name,int source,cothread_context *ctx) {
|
||||
looper *l = malloc(sizeof(looper));
|
||||
|
||||
if (l == NULL) {
|
||||
fprintf(stderr,"sorry, couldn't allocate memory for looper\n");
|
||||
exit(2);
|
||||
}
|
||||
object_init(OBJECT(l),name,ctx);
|
||||
looper_init(l,source);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
void looper_loopfunc(object *obj) {
|
||||
looper *l = LOOPER(obj);
|
||||
|
||||
if (l->source) {
|
||||
while (1) {
|
||||
char *buf = malloc(11);
|
||||
sprintf(buf,"Hello World!");
|
||||
fprintf(stderr,"\npushing buffer %p with '%s'\n",buf,buf);
|
||||
object_push(OBJECT(l)->peer,buf); // this should switch
|
||||
}
|
||||
} else {
|
||||
while (1) {
|
||||
char *buf;
|
||||
fprintf(stderr,"\npulling buffer\n");
|
||||
buf = object_pull(OBJECT(l));
|
||||
printf("got %p: '%s' from peer\n",buf,buf);
|
||||
free(buf);
|
||||
// return to the main process now
|
||||
cothread_switch(cothread_main(OBJECT(l)->threadstate->ctx));
|
||||
sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
18
test/cothreads/looper.h
Normal file
18
test/cothreads/looper.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef __LOOPER_H__
|
||||
#define __LOOPER_H__
|
||||
|
||||
#include "object.h"
|
||||
|
||||
#define LOOPER(l) ((looper *)(l))
|
||||
|
||||
typedef struct _looper looper;
|
||||
struct _looper {
|
||||
object object;
|
||||
|
||||
int source;
|
||||
};
|
||||
|
||||
void looper_init(looper *l,int source);
|
||||
looper *looper_create(char *name,int source,cothread_context *ctx);
|
||||
|
||||
#endif /* __LOOPER_H__ */
|
78
test/cothreads/object.c
Normal file
78
test/cothreads/object.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include <stdio.h>
|
||||
#include "object.h"
|
||||
|
||||
int object_loop_function(int argc,char **argv) {
|
||||
object *obj = OBJECT(argv);
|
||||
printf("hey, in loopfunc for object %p\n",obj);
|
||||
obj->loopfunc(obj);
|
||||
}
|
||||
|
||||
void object_init(object *obj,char *name,cothread_context *ctx) {
|
||||
obj->threadstate = cothread_create(ctx);
|
||||
cothread_setfunc(obj->threadstate,object_loop_function,0,(char **)obj);
|
||||
if (obj->threadstate == NULL) {
|
||||
fprintf(stderr,"sorry, couldn't init threadstate\n");
|
||||
exit(2);
|
||||
}
|
||||
obj->loopfunc = NULL;
|
||||
obj->name = malloc(strlen(name));
|
||||
memcpy(obj->name,name,strlen(name));
|
||||
obj->peer = NULL;
|
||||
}
|
||||
|
||||
object *object_create(char *name,cothread_context *ctx) {
|
||||
object *obj = malloc(sizeof(object));
|
||||
|
||||
if (obj == NULL) {
|
||||
printf("ack!\n");
|
||||
exit(2);
|
||||
}
|
||||
memset(obj,0,sizeof(object));
|
||||
object_init(obj,name,ctx);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void object_setloopfunc(object *obj,object_loopfunc func) {
|
||||
obj->loopfunc = func;
|
||||
fprintf(stderr,"setting object loopfunc to %p\n",func);
|
||||
}
|
||||
|
||||
void object_setpeer(object *obj,object *peer) {
|
||||
obj->peer = peer;
|
||||
peer->peer = obj;
|
||||
printf("peered %p and %p\n",obj,peer);
|
||||
}
|
||||
|
||||
void object_push(object *obj,char *buf) {
|
||||
obj->pen = buf;
|
||||
cothread_switch(obj->threadstate);
|
||||
}
|
||||
|
||||
char *object_pull(object *obj) {
|
||||
char *buf,i=0;
|
||||
|
||||
if (obj == NULL) fprintf(stderr,"obj is null\n");
|
||||
if (obj->peer == NULL) fprintf(stderr,"obj->peer is null\n");
|
||||
if (obj->peer->threadstate == NULL) fprintf(stderr,"obj->peer->threadstate is null\n");
|
||||
|
||||
while (obj->pen == NULL)
|
||||
cothread_switch(obj->peer->threadstate),i++;
|
||||
buf = obj->pen;
|
||||
obj->pen = NULL;
|
||||
|
||||
fprintf(stderr,"took %d switches to get %p from pen\n",i,buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void object_start(object *obj) {
|
||||
if (!obj->threadstate || !obj->loopfunc) {
|
||||
fprintf(stderr,"ack, not complete\n");
|
||||
fprintf(stderr,"obj->threadstate is %p, obj->loopfunc is %p\n",
|
||||
obj->threadstate,obj->loopfunc);
|
||||
exit(2);
|
||||
}
|
||||
cothread_switch(obj->threadstate);
|
||||
fprintf(stderr,"returned from cothread stuff into end of object_start()\n");
|
||||
}
|
30
test/cothreads/object.h
Normal file
30
test/cothreads/object.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef __OBJECT_H__
|
||||
#define __OBJECT_H__
|
||||
|
||||
#include "cothreads.h"
|
||||
|
||||
#define OBJECT(obj) ((object*)(obj))
|
||||
|
||||
typedef struct _object object;
|
||||
|
||||
typedef void (*object_loopfunc)(object *obj);
|
||||
|
||||
struct _object {
|
||||
cothread_state *threadstate;
|
||||
object_loopfunc loopfunc;
|
||||
|
||||
char *name;
|
||||
object *peer;
|
||||
|
||||
void *pen;
|
||||
};
|
||||
|
||||
void object_init(object *obj,char *name,cothread_context *ctx);
|
||||
object *object_create(char *name,cothread_context *ctx);
|
||||
void object_setloopfunc(object *obj,object_loopfunc func);
|
||||
void object_setpeer(object *obj,object *peer);
|
||||
void object_push(object *obj,char *buf);
|
||||
char *object_pull(object *obj);
|
||||
int object_loop_function(int argc,char **argv);
|
||||
|
||||
#endif /* __OBJECT_H__ */
|
23
test/cothreads/simple.c
Normal file
23
test/cothreads/simple.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <stdio.h>
|
||||
#include "cothreads.h"
|
||||
|
||||
// cothread_context is passed in argv
|
||||
int loopfunc(int argc,char **argv) {
|
||||
fprintf(stderr,"SIMPLE: in loopfunc\n");
|
||||
cothread_switch((cothread_context *)cothread_main(argv));
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
cothread_context *ctx;
|
||||
cothread_state *state;
|
||||
|
||||
ctx = cothread_init();
|
||||
state = cothread_create(ctx);
|
||||
cothread_setfunc(state,loopfunc,0,(char **)ctx);
|
||||
|
||||
fprintf(stderr,"SIMPLE: about to switch to cothread 1\n");
|
||||
cothread_switch(state);
|
||||
fprintf(stderr,"SIMPLE: back from cothread_switch\n");
|
||||
|
||||
return 0;
|
||||
}
|
17
test/cothreads/test.c
Normal file
17
test/cothreads/test.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "cothreads.h"
|
||||
#include "object.h"
|
||||
#include "looper.h"
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
cothread_context *ctx = cothread_init();
|
||||
looper *l1,*l2;
|
||||
|
||||
l1 = looper_create("looperone",1,ctx);
|
||||
l2 = looper_create("loopertwo",0,ctx);
|
||||
object_setpeer(OBJECT(l1),OBJECT(l2));
|
||||
|
||||
fprintf(stderr,"about to start l1\n\n");
|
||||
object_start(l1);
|
||||
}
|
46
test/dvdcat.c
Normal file
46
test/dvdcat.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *pipeline;
|
||||
GstElement *src, *sink;
|
||||
int fd;
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
// gst_plugin_load("dvdsrc");
|
||||
|
||||
fd = creat("output.vob",0644);
|
||||
|
||||
pipeline = gst_elementfactory_make("pipeline","dvdcat");
|
||||
g_return_if_fail(pipeline != NULL);
|
||||
|
||||
src = gst_elementfactory_make("dvdsrc","src");
|
||||
g_return_if_fail(src != NULL);
|
||||
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
|
||||
if (argc >= 3)
|
||||
gtk_object_set(GTK_OBJECT(src),"offset",atoi(argv[2]),NULL);
|
||||
sink = gst_elementfactory_make("fdsink","sink");
|
||||
g_return_if_fail(sink != NULL);
|
||||
gtk_object_set(GTK_OBJECT(sink),"fd",fd,NULL);
|
||||
|
||||
// construct the outer pipeline
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(sink));
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
|
||||
|
||||
// while (GST_STATE_IS_SET(src,GST_STATE_RUNNING))
|
||||
// while (1)
|
||||
while (GST_STATE_IS_SET(src,1<<16))
|
||||
gst_src_push(GST_SRC(src));
|
||||
}
|
37
test/fake.c
Normal file
37
test/fake.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstPipeline *pipeline;
|
||||
GstElement *src, *sink;
|
||||
GstPad *srcpad, *sinkpad;
|
||||
|
||||
// _gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
pipeline = gst_pipeline_new("pipeline");
|
||||
g_return_if_fail(pipeline != NULL);
|
||||
|
||||
g_print("--- creating src and sink elements\n");
|
||||
src = gst_elementfactory_make("fakesrc","src");
|
||||
g_return_if_fail(src != NULL);
|
||||
sink = gst_elementfactory_make("fakesink","sink");
|
||||
g_return_if_fail(sink != NULL);
|
||||
|
||||
g_print("--- about to add the elements to the pipeline\n");
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(sink));
|
||||
|
||||
g_print("--- getting pads\n");
|
||||
srcpad = gst_element_get_pad(src,"src");
|
||||
g_return_if_fail(srcpad != NULL);
|
||||
sinkpad = gst_element_get_pad(sink,"sink");
|
||||
g_return_if_fail(srcpad != NULL);
|
||||
|
||||
g_print("--- connecting\n");
|
||||
gst_pad_connect(srcpad,sinkpad);
|
||||
|
||||
g_print("--- setting up\n");
|
||||
gst_pipeline_iterate(pipeline);
|
||||
}
|
15
test/gsttracedump.c
Normal file
15
test/gsttracedump.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <glib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <gst/gsttrace.h>
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
gchar *filename = argv[1];
|
||||
int fd = open(filename,O_RDONLY);
|
||||
GstTraceEntry entry;
|
||||
|
||||
while (read(fd,&entry,sizeof(entry)))
|
||||
g_print("%Ld(%ld) 0x%08lx: %s\n",entry.timestamp,entry.sequence,
|
||||
entry.data,entry.message);
|
||||
}
|
26
test/jitter.c
Normal file
26
test/jitter.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
char line[256];
|
||||
unsigned long long a = 0,b;
|
||||
unsigned long long difference;
|
||||
unsigned long long mindiff = -1, maxdiff = 0;
|
||||
unsigned long long total = 0;
|
||||
int samples = 0;
|
||||
|
||||
while (gets(line)) {
|
||||
sscanf(line,"%Ld",&b);
|
||||
if (a) {
|
||||
difference = b - a;
|
||||
printf("difference is %Ld\n",difference);
|
||||
if (difference > maxdiff) maxdiff = difference;
|
||||
if (difference < mindiff) mindiff = difference;
|
||||
total += difference;
|
||||
samples++;
|
||||
}
|
||||
a = b;
|
||||
}
|
||||
printf("min difference is %Ld, avg %Ld, max is %Ld\n",
|
||||
mindiff,total/samples,maxdiff);
|
||||
printf("jitter is %Ld\n",maxdiff-mindiff);
|
||||
}
|
76
test/m.c
Normal file
76
test/m.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include <gst/gst.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
g_print("eof\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
guint16 type;
|
||||
GList *factories;
|
||||
GstElementFactory *parsefactory;
|
||||
GstElement *bin, *src, *parse, *sink;
|
||||
GList *padlist;
|
||||
guchar *filename;
|
||||
|
||||
if (argc == 2)
|
||||
filename = argv[1];
|
||||
else
|
||||
filename = "-";
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
if (!strcmp(filename,"-"))
|
||||
src = gst_fdsrc_new_with_fd("src",STDIN_FILENO);
|
||||
else if (!strncmp(filename,"http://",7))
|
||||
src = gst_httpsrc_new_with_url("src",filename);
|
||||
else
|
||||
src = gst_asyncdisksrc_new_with_file("src",filename);
|
||||
|
||||
/* now it's time to get the parser */
|
||||
type = gst_type_find_by_mime("audio/mpeg");
|
||||
factories = gst_type_get_sinks(type);
|
||||
if (factories != NULL)
|
||||
parsefactory = GST_ELEMENTFACTORY(factories->data);
|
||||
else {
|
||||
g_print("sorry, can't find anyone registered to sink 'mp3'\n");
|
||||
return 1;
|
||||
}
|
||||
parse = gst_elementfactory_create(parsefactory,"parser");
|
||||
if (parse == NULL) {
|
||||
g_print("sorry, couldn't create parser\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
sink = gst_audiosink_new("audiosink");
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(src),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),src);
|
||||
gst_bin_add(GST_BIN(bin),parse);
|
||||
gst_bin_add(GST_BIN(bin),sink);
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
while(1) {
|
||||
g_print(".");
|
||||
gst_src_push(GST_SRC(src));
|
||||
}
|
||||
|
||||
gst_object_destroy(GST_OBJECT(sink));
|
||||
gst_object_destroy(GST_OBJECT(parse));
|
||||
gst_object_destroy(GST_OBJECT(src));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
77
test/mcut.c
Normal file
77
test/mcut.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
g_print("have eof, quitting\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstType *type;
|
||||
GList *factories;
|
||||
GstElementFactory *parsefactory;
|
||||
GstElement *bin, *src, *parse, *sink;
|
||||
GList *padlist;
|
||||
guchar *filename;
|
||||
glong length = 0, size = 4180, skip = 8360, offset = 0;
|
||||
|
||||
if (argc == 2)
|
||||
filename = argv[1];
|
||||
else {
|
||||
g_print("sorry, need a filename now\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
src = gst_asyncdisksrc_new("src");
|
||||
g_print("created disksrc\n");
|
||||
gtk_object_set(GTK_OBJECT(src),"location",filename,NULL);
|
||||
length = gst_util_get_long_arg(GST_OBJECT(src),"length");
|
||||
g_print("file is %d bytes long\n",length);
|
||||
|
||||
/* now it's time to get the parser */
|
||||
type = gst_type_get_by_mime("audio/mp3");
|
||||
factories = gst_type_get_sinks(type);
|
||||
if (factories != NULL)
|
||||
parsefactory = GST_ELEMENTFACTORY(factories->data);
|
||||
else {
|
||||
g_print("sorry, can't find anyone registered to sink 'mp3'\n");
|
||||
return 1;
|
||||
}
|
||||
parse = gst_elementfactory_create(parsefactory,"parser");
|
||||
if (parse == NULL) {
|
||||
g_print("sorry, couldn't create parser\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
sink = gst_audiosink_new("audiosink");
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(src),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),src);
|
||||
gst_bin_add(GST_BIN(bin),parse);
|
||||
gst_bin_add(GST_BIN(bin),sink);
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
while(offset < length) {
|
||||
gst_src_push_region(GST_SRC(src),offset,size);
|
||||
offset += skip;
|
||||
}
|
||||
|
||||
gst_object_destroy(GST_OBJECT(sink));
|
||||
gst_object_destroy(GST_OBJECT(parse));
|
||||
gst_object_destroy(GST_OBJECT(src));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
22
test/mem.c
Normal file
22
test/mem.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int vmsize() {
|
||||
int pid,fd,size,i,mem;
|
||||
char filename[17], buf[256], *ptr, *end;
|
||||
|
||||
pid = getpid();
|
||||
snprintf(filename,17,"/proc/%d/stat",pid);
|
||||
fd = open(filename,O_RDONLY);
|
||||
size = read(fd,buf,240);
|
||||
ptr = buf;
|
||||
for (i=0;i<22;i++)
|
||||
ptr = (char *)strchr(ptr,' ') + 1;
|
||||
end = (char *)strchr(ptr,' ');
|
||||
*end = 0;
|
||||
sscanf(ptr,"%d",&mem);
|
||||
close(fd);
|
||||
return mem;
|
||||
}
|
1
test/mem.h
Normal file
1
test/mem.h
Normal file
|
@ -0,0 +1 @@
|
|||
int vmsize();
|
63
test/mp3.c
Normal file
63
test/mp3.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include <gnome.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
static gboolean playing = TRUE;
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
DEBUG("have EOF\n");
|
||||
playing = FALSE;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *bin;
|
||||
GstElementFactory *srcfactory;
|
||||
GstElement *src;
|
||||
GstElementFactory *mp3factory;
|
||||
GstElement *mp3;
|
||||
GstElementFactory *sinkfactory;
|
||||
GstElement *sink;
|
||||
|
||||
GtkWidget *appwindow;
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
srcfactory = gst_elementfactory_find("disksrc");
|
||||
if (argc == 3)
|
||||
mp3factory = gst_elementfactory_find(argv[2]);
|
||||
else
|
||||
mp3factory = gst_elementfactory_find("xa");
|
||||
sinkfactory = gst_elementfactory_find("audiosink");
|
||||
|
||||
src = gst_elementfactory_create(srcfactory,"src");
|
||||
g_return_if_fail(src != NULL);
|
||||
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
|
||||
mp3 = gst_elementfactory_create(mp3factory,"mp3");
|
||||
g_return_if_fail(mp3 != NULL);
|
||||
sink = gst_elementfactory_create(sinkfactory,"sink");
|
||||
g_return_if_fail(sink != NULL);
|
||||
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(mp3));
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(sink));
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(mp3,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(mp3,"src"),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(src),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_RUNNING);
|
||||
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_PLAYING);
|
||||
|
||||
while (playing)
|
||||
gst_src_push(GST_SRC(src));
|
||||
}
|
55
test/mp3parse.c
Normal file
55
test/mp3parse.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
void mp3parse_info_chain(GstPad *pad,GstBuffer *buf) {
|
||||
g_print("got buffer of size %d\n",GST_BUFFER_SIZE(buf));
|
||||
gst_buffer_unref(buf);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstPipeline *pipeline;
|
||||
GstElementFactory *srcfactory, *parsefactory;
|
||||
GstElement *src, *parse;
|
||||
GstPad *infopad;
|
||||
|
||||
g_print("have %d args\n",argc);
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
// gst_plugin_load("mp3parse");
|
||||
gst_plugin_load_all();
|
||||
|
||||
pipeline = gst_pipeline_new("pipeline");
|
||||
g_return_if_fail(pipeline != NULL);
|
||||
|
||||
srcfactory = gst_elementfactory_find("disksrc");
|
||||
g_return_if_fail(srcfactory != NULL);
|
||||
parsefactory = gst_elementfactory_find("mp3parse");
|
||||
g_return_if_fail(parsefactory != NULL);
|
||||
|
||||
src = gst_elementfactory_create(srcfactory,"src");
|
||||
g_return_if_fail(src != NULL);
|
||||
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
|
||||
g_print("should be using file '%s'\n",argv[1]);
|
||||
parse = gst_elementfactory_create(parsefactory,"parse");
|
||||
g_return_if_fail(parse != NULL);
|
||||
|
||||
infopad = gst_pad_new("sink",GST_PAD_SINK);
|
||||
gst_pad_set_chain_function(infopad,mp3parse_info_chain);
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
infopad);
|
||||
|
||||
g_print("setting to RUNNING state\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
|
||||
|
||||
g_print("about to enter loop\n");
|
||||
while (1)
|
||||
gst_src_push(GST_SRC(src));
|
||||
}
|
59
test/mp3play.c
Normal file
59
test/mp3play.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstPipeline *pipeline;
|
||||
GstElementFactory *srcfactory, *parsefactory, *decodefactory, *playfactory;
|
||||
GstElement *src, *parse, *decode, *play;
|
||||
GstPad *infopad;
|
||||
|
||||
g_print("have %d args\n",argc);
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
// gst_plugin_load("mp3parse");
|
||||
gst_plugin_load_all();
|
||||
|
||||
pipeline = gst_pipeline_new("pipeline");
|
||||
g_return_if_fail(pipeline != NULL);
|
||||
|
||||
srcfactory = gst_elementfactory_find("disksrc");
|
||||
g_return_if_fail(srcfactory != NULL);
|
||||
parsefactory = gst_elementfactory_find("mp3parse");
|
||||
g_return_if_fail(parsefactory != NULL);
|
||||
decodefactory = gst_elementfactory_find("mpg123");
|
||||
g_return_if_fail(decodefactory != NULL);
|
||||
playfactory = gst_elementfactory_find("audiosink");
|
||||
g_return_if_fail(playfactory != NULL);
|
||||
|
||||
src = gst_elementfactory_create(srcfactory,"src");
|
||||
g_return_if_fail(src != NULL);
|
||||
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
|
||||
g_print("should be using file '%s'\n",argv[1]);
|
||||
parse = gst_elementfactory_create(parsefactory,"parse");
|
||||
g_return_if_fail(parse != NULL);
|
||||
decode = gst_elementfactory_create(decodefactory,"decode");
|
||||
g_return_if_fail(decode != NULL);
|
||||
play = gst_elementfactory_create(playfactory,"play");
|
||||
g_return_if_fail(play != NULL);
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(decode));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(play));
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
gst_element_get_pad(decode,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(decode,"src"),
|
||||
gst_element_get_pad(play,"sink"));
|
||||
|
||||
g_print("setting to RUNNING state\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
|
||||
|
||||
g_print("about to enter loop\n");
|
||||
while (1)
|
||||
gst_src_push(GST_SRC(src));
|
||||
}
|
95
test/mpeg2parse.c
Normal file
95
test/mpeg2parse.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
static int ac3fd;
|
||||
static gchar *desired_stream;
|
||||
|
||||
void mpeg2parse_write_ac3(GstPad *pad,GstBuffer *buf) {
|
||||
g_print(".");
|
||||
// g_print("MPEG2PARSE: got AC3 buffer of size %d\n",GST_BUFFER_SIZE(buf));
|
||||
write(ac3fd,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
|
||||
gst_buffer_unref(buf);
|
||||
}
|
||||
|
||||
void mpeg2parse_info_chain(GstPad *pad,GstBuffer *buf) {
|
||||
// g_print("MPEG2PARSE: got buffer of size %d\n",GST_BUFFER_SIZE(buf));
|
||||
gst_buffer_unref(buf);
|
||||
}
|
||||
|
||||
void mpeg2parse_newpad(GstElement *parser,GstPad *pad) {
|
||||
GstPad *infopad;
|
||||
|
||||
g_print("MPEG2PARSE: have new pad \"%s\" from parser\n",
|
||||
gst_pad_get_name(pad));
|
||||
|
||||
infopad = gst_pad_new("sink",GST_PAD_SINK);
|
||||
if (strcmp(gst_pad_get_name(pad),desired_stream) == 0)
|
||||
gst_pad_set_chain_function(infopad,mpeg2parse_write_ac3);
|
||||
else
|
||||
gst_pad_set_chain_function(infopad,mpeg2parse_info_chain);
|
||||
gst_pad_connect(pad,infopad);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstPipeline *pipeline;
|
||||
GstElement *src, *parse, *out;
|
||||
GstPad *infopad;
|
||||
int i,c;
|
||||
|
||||
g_print("have %d args\n",argc);
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
// gst_plugin_load("mpeg2parse");
|
||||
gst_plugin_load_all();
|
||||
|
||||
ac3fd = creat("output.ac3",S_IREAD|S_IWRITE);
|
||||
|
||||
pipeline = gst_pipeline_new("pipeline");
|
||||
g_return_if_fail(pipeline != NULL);
|
||||
|
||||
if (strstr(argv[1],"video_ts")) {
|
||||
src = gst_elementfactory_make("dvdsrc","src");
|
||||
g_print("using DVD source\n");
|
||||
} else
|
||||
src = gst_elementfactory_make("disksrc","src");
|
||||
g_return_if_fail(src != NULL);
|
||||
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
|
||||
if (argc >= 3) {
|
||||
gtk_object_set(GTK_OBJECT(src),"bytesperread",atoi(argv[2]),NULL);
|
||||
g_print("block size is %d\n",atoi(argv[2]));
|
||||
}
|
||||
g_print("should be using file '%s'\n",argv[1]);
|
||||
|
||||
parse = gst_elementfactory_make("mpeg2parse","parse");
|
||||
g_return_if_fail(parse != NULL);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad,NULL);
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
|
||||
g_print("setting to RUNNING state\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
|
||||
|
||||
if (argc >= 4) c = atoi(argv[3]);
|
||||
else c = 4;
|
||||
g_print("c is %d\n",c);
|
||||
|
||||
if (argc >= 5) desired_stream = argv[4];
|
||||
else desired_stream = "private_stream_1.0";
|
||||
|
||||
g_print("\n");
|
||||
for (i=0;i<c;i++) {
|
||||
g_print("\n");
|
||||
gst_src_push(GST_SRC(src));
|
||||
}
|
||||
}
|
67
test/mpg123.c
Normal file
67
test/mpg123.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
g_print("have eof, quitting\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GList *factories;
|
||||
GstElementFactory *parsefactory;
|
||||
GstElement *bin, *disksrc, *parse, *audiosink;
|
||||
GList *padlist;
|
||||
guchar *filename;
|
||||
int i;
|
||||
|
||||
if (argc == 2)
|
||||
filename = argv[1];
|
||||
else
|
||||
filename = "ctp2.mp3";
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
g_print("\n");
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
disksrc = gst_disksrc_new("disksrc");
|
||||
g_print("created disksrc\n");
|
||||
gtk_object_set(GTK_OBJECT(disksrc),"location",filename,NULL);
|
||||
gtk_object_set(GTK_OBJECT(disksrc),"bytesperread",1048576,NULL);
|
||||
|
||||
/* now it's time to get the parser */
|
||||
parsefactory = gst_plugin_find_elementfactory("xing");
|
||||
parse = gst_elementfactory_create(parsefactory,"parser");
|
||||
if (parse == NULL) {
|
||||
g_print("sorry, couldn't create parser\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
audiosink = gst_audiosink_new("audiosink");
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
gst_element_get_pad(audiosink,"sink"));
|
||||
|
||||
for (i=0;i<4;i++) {
|
||||
g_print("\n");
|
||||
gst_disksrc_push(GST_SRC(disksrc));
|
||||
}
|
||||
|
||||
gst_object_destroy(GST_OBJECT(audiosink));
|
||||
gst_object_destroy(GST_OBJECT(parse));
|
||||
gst_object_destroy(GST_OBJECT(disksrc));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
55
test/p.c
Normal file
55
test/p.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
g_print("have eof, quitting\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *bin, *disksrc, *p, *audiosink;
|
||||
GList *padlist;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
disksrc = gst_disksrc_new("disksrc");
|
||||
g_print("created disksrc\n");
|
||||
if (argc == 2)
|
||||
gst_disksrc_set_filename(disksrc,argv[1]);
|
||||
else
|
||||
gst_disksrc_set_filename(disksrc,"mendelssohn.1.raw");
|
||||
gst_disksrc_set_bytesperread(disksrc,32768);
|
||||
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
|
||||
|
||||
p = gst_plugin_find_elementfactory("pipe");
|
||||
audiosink = gst_audiosink_new("audiosink");
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(p));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
|
||||
gst_element_get_pad(p,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(p,"src"),
|
||||
gst_element_get_pad(audiosink,"sink"));
|
||||
|
||||
/* set soundcard properties */
|
||||
gst_audiosink_set_format(GST_AUDIOSINK(audiosink),AFMT_S16_BE);
|
||||
gst_audiosink_set_channels(GST_AUDIOSINK(audiosink),2);
|
||||
gst_audiosink_set_frequency(GST_AUDIOSINK(audiosink),44100);
|
||||
|
||||
while(1)
|
||||
gst_disksrc_push(GST_SRC(disksrc));
|
||||
|
||||
gst_object_destroy(GST_OBJECT(audiosink));
|
||||
gst_object_destroy(GST_OBJECT(disksrc));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
17
test/plugin.c
Normal file
17
test/plugin.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElementFactory *parseau_factory;
|
||||
GstElement *parseau;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
gst_plugin_load_all();
|
||||
|
||||
parseau_factory = gst_plugin_find_elementfactory("parseau");
|
||||
g_print("parseau_factory is %p\n",parseau_factory);
|
||||
|
||||
parseau = gst_elementfactory_create(parseau_factory,"parser");
|
||||
g_print("got parseau '%s' from plugin!!!\n",
|
||||
gst_object_get_name(GST_OBJECT(parseau)));
|
||||
}
|
78
test/push.c
Normal file
78
test/push.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
int eofflag = 0;
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
eofflag = 1;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
struct sockaddr_in src_addr, dst_addr;
|
||||
int sockaddrlen;
|
||||
int lsock;
|
||||
int one = 1;
|
||||
int sndbuf = 4096;
|
||||
int sock;
|
||||
GstElement *src,*sink;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
lsock = socket(AF_INET,SOCK_STREAM,0);
|
||||
if (lsock < 0) {
|
||||
perror("creating socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setsockopt(lsock,SOL_SOCKET,SO_REUSEADDR,&one,sizeof(one))) {
|
||||
perror("setsockopt(SO_REUSEADDR)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
src_addr.sin_family = AF_INET;
|
||||
src_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
src_addr.sin_port = htons(8001);
|
||||
|
||||
if (bind(lsock,(struct sockaddr *)&src_addr,sizeof(src_addr))) {
|
||||
perror("binding");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setsockopt(lsock,SOL_SOCKET,SO_SNDBUF,(char *)&sndbuf,sizeof(sndbuf))) {
|
||||
perror("setsockopt(SO_SNDBUF)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
g_print("listening\n");
|
||||
listen(lsock,8);
|
||||
|
||||
sock = accept(lsock,(struct sockaddr *)&dst_addr,&sockaddrlen);
|
||||
g_print("connected\n");
|
||||
|
||||
close(lsock);
|
||||
|
||||
g_print("creating pipeline\n");
|
||||
src = gst_disksrc_new_with_location("src",argv[1]);
|
||||
g_print("have src\n");
|
||||
gtk_signal_connect(GTK_OBJECT(src),"eof",GTK_SIGNAL_FUNC(eof),NULL);
|
||||
g_print("have eof signal\n");
|
||||
sink = gst_fdsink_new_with_fd("sink",sock);
|
||||
g_print("have sink\n");
|
||||
|
||||
g_print("connecting\n");
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
g_print("pushing...\n");
|
||||
while (!eofflag)
|
||||
gst_src_push(GST_SRC(src));
|
||||
|
||||
sleep(1);
|
||||
close(sock);
|
||||
}
|
104
test/qtest.c
Normal file
104
test/qtest.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/elements/gstqueue.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
/* we don't need a lock around the application's state yet, since it's 1
|
||||
bit. as it gets more fleshed in, we'll need a lock so the callbacks
|
||||
don't screw around with state unexpectedly */
|
||||
static gboolean playing = TRUE;
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
DEBUG("have EOF\n");
|
||||
playing = FALSE;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *pipeline;
|
||||
GstElement *decodethread;
|
||||
GstElementFactory *srcfactory;
|
||||
GstElement *src;
|
||||
GstElementFactory *decodefactory;
|
||||
GstElement *decode;
|
||||
GstElementFactory *queuefactory;
|
||||
GstElement *queue;
|
||||
GstElement *playthread;
|
||||
GstElementFactory *sinkfactory;
|
||||
GstElement *sink;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
/* first create the main pipeline */
|
||||
pipeline = gst_pipeline_new("pipeline");
|
||||
|
||||
/* then the decode thread, source, and decoder */
|
||||
decodethread = gst_thread_new("decodethread");
|
||||
|
||||
srcfactory = gst_elementfactory_find("asyncdisksrc");
|
||||
src = gst_elementfactory_create(srcfactory,"src");
|
||||
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
|
||||
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(src));
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
|
||||
if (argc > 2)
|
||||
gst_plugin_load(argv[2]);
|
||||
else
|
||||
gst_plugin_load_all();
|
||||
decodefactory = gst_elementfactory_find("mpg123");
|
||||
decode = gst_elementfactory_create(decodefactory,"decode");
|
||||
gst_bin_add(GST_BIN(decodethread),GST_ELEMENT(decode));
|
||||
gst_element_add_ghost_pad(GST_ELEMENT(decodethread),
|
||||
gst_element_get_pad(decode,"src"));
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(decode,"sink"));
|
||||
|
||||
/* then the play thread and sink */
|
||||
playthread = gst_thread_new("playthread");
|
||||
|
||||
sinkfactory = gst_elementfactory_find("audiosink");
|
||||
sink = gst_elementfactory_create(sinkfactory,"sink");
|
||||
gst_bin_add(GST_BIN(playthread),GST_ELEMENT(sink));
|
||||
gst_element_add_ghost_pad(GST_ELEMENT(playthread),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
/* create the queue */
|
||||
queuefactory = gst_elementfactory_find("queue");
|
||||
queue = gst_elementfactory_create(queuefactory,"queue");
|
||||
|
||||
/* add threads to the main pipeline */
|
||||
gst_bin_add(GST_BIN(pipeline),decodethread);
|
||||
gst_bin_add(GST_BIN(pipeline),queue);
|
||||
gst_bin_add(GST_BIN(pipeline),playthread);
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(decodethread,"src"),
|
||||
// gst_element_get_pad(queue,"sink"));
|
||||
// gst_pad_connect(gst_element_get_pad(queue,"src"),
|
||||
gst_element_get_pad(playthread,"sink"));
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(src),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
g_print("\nsetting up the decode thread to *NOT* thread\n");
|
||||
// gtk_object_set(GTK_OBJECT(decodethread),"create_thread",TRUE,NULL);
|
||||
gtk_object_set(GTK_OBJECT(playthread),"create_thread",FALSE,NULL);
|
||||
|
||||
g_print("\neverything's built, setting it up to be runnable\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
|
||||
|
||||
g_print("\nok, runnable, hitting 'play'...\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
|
||||
|
||||
g_print("\niterating on %p and %p\n",decodethread,playthread);
|
||||
while (playing) {
|
||||
gst_thread_iterate(GST_THREAD(playthread));
|
||||
/* buffers got wedged in the queue, unstick them */
|
||||
// while (((GstQueue *)queue)->buffers_queued)
|
||||
// gst_connection_push(GST_CONNECTION(queue));
|
||||
// gst_thread_iterate(GST_THREAD(playthread));
|
||||
// g_print("stuffed and unstuck the queue\n");
|
||||
// sleep(1);
|
||||
}
|
||||
}
|
51
test/r.c
Normal file
51
test/r.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
g_print("have eof, quitting\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *bin, *disksrc, *audiosink;
|
||||
GList *padlist;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
disksrc = gst_disksrc_new("disksrc");
|
||||
g_print("created disksrc\n");
|
||||
if (argc == 2)
|
||||
gst_disksrc_set_filename(disksrc,argv[1]);
|
||||
else
|
||||
gst_disksrc_set_filename(disksrc,"mendelssohn.1.raw");
|
||||
gtk_object_set(GTK_OBJECT(disksrc),"bytesperread",32768,NULL);
|
||||
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
|
||||
|
||||
audiosink = gst_audiosink_new("audiosink");
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
|
||||
gst_element_get_pad(audiosink,"sink"));
|
||||
|
||||
/* set soundcard properties */
|
||||
gst_audiosink_set_format(GST_AUDIOSINK(audiosink),AFMT_S16_BE);
|
||||
gst_audiosink_set_channels(GST_AUDIOSINK(audiosink),2);
|
||||
gst_audiosink_set_frequency(GST_AUDIOSINK(audiosink),44100);
|
||||
|
||||
while(1)
|
||||
gst_disksrc_push(GST_SRC(disksrc));
|
||||
|
||||
gst_object_destroy(GST_OBJECT(audiosink));
|
||||
gst_object_destroy(GST_OBJECT(disksrc));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
43
test/record.c
Normal file
43
test/record.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
int fd;
|
||||
GstElement *pipeline, *audiosrc, *fdsink;
|
||||
GstElementFactory *audiosrcfactory, *fdsinkfactory;
|
||||
GList *padlist;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
pipeline = gst_pipeline_new("pipeline");
|
||||
|
||||
audiosrcfactory = gst_elementfactory_find("audiosrc");
|
||||
audiosrc = gst_elementfactory_create(audiosrcfactory,"audiosrc");
|
||||
|
||||
fd = open(argv[1],O_CREAT|O_RDWR);
|
||||
|
||||
fdsinkfactory = gst_elementfactory_find("fdsink");
|
||||
fdsink = gst_elementfactory_create(fdsinkfactory,"fdsink");
|
||||
gtk_object_set(GTK_OBJECT(fdsink),"fd",fd,NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(audiosrc));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(fdsink));
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(audiosrc,"src"),
|
||||
gst_element_get_pad(fdsink,"sink"));
|
||||
|
||||
g_print("\neverything's built, setting it up to be runnable\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
|
||||
|
||||
g_print("\nok, runnable, hitting 'play'...\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
|
||||
|
||||
while(1)
|
||||
gst_src_push(GST_SRC(audiosrc));
|
||||
}
|
||||
|
116
test/s.c
Normal file
116
test/s.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
#include <ghttp.h>
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
g_print("have eof, quitting\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
guint16 mp3type;
|
||||
GList *factories;
|
||||
GstElementFactory *parsefactory;
|
||||
GstElement *bin, *src, *parse, *audiosink;
|
||||
GList *padlist;
|
||||
ghttp_request *pls;
|
||||
guchar *plsbuf;
|
||||
gint plsbuflen,parsedlen = 0;
|
||||
guchar *url,*local;
|
||||
GSList *urls = NULL;
|
||||
|
||||
pls = ghttp_request_new();
|
||||
if (argc >= 2)
|
||||
ghttp_set_uri(pls,argv[1]);
|
||||
else
|
||||
ghttp_set_uri(pls,"http://209.127.18.4:9000");
|
||||
ghttp_prepare(pls);
|
||||
ghttp_process(pls);
|
||||
plsbuf = ghttp_get_body(pls);
|
||||
plsbuflen = ghttp_get_body_len(pls);
|
||||
|
||||
while (parsedlen < plsbuflen) {
|
||||
local = plsbuf + parsedlen;
|
||||
if ((*local != '[') && (*local != '\n')) { /* t/v pair */
|
||||
if (!strncmp(local,"File1=",4)) { /* if file */
|
||||
url = strchr(local,'=') + 1; /* url after = */
|
||||
local = strchr(url,'\n'); /* ffwd after = */
|
||||
*(local)++ = 0; /* nullz url */
|
||||
g_print("prepending '%s' to list\n",url);
|
||||
urls = g_slist_prepend(urls,g_strdup(url));
|
||||
/* local should point to next line now */
|
||||
} else {
|
||||
local = strchr(local,'\n') + 1; /* skip line */
|
||||
}
|
||||
} else {
|
||||
local = strchr(local,'\n') + 1; /* skip line */
|
||||
}
|
||||
/* we can consider that line parsed... */
|
||||
parsedlen = local - plsbuf;
|
||||
}
|
||||
if (urls == NULL) {
|
||||
g_print("couldn't find any streams\n");
|
||||
exit(1);
|
||||
}
|
||||
ghttp_request_destroy(pls);
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
src = gst_httpsrc_new("src");
|
||||
if (argc == 3) {
|
||||
int i;
|
||||
for (i=1;i<atoi(argv[2]);i++)
|
||||
urls = g_slist_next(urls);
|
||||
}
|
||||
g_print("loading shoutcast server %s\n",urls->data);
|
||||
gtk_object_set(GTK_OBJECT(src),"location",urls->data,NULL);
|
||||
g_print("created src\n");
|
||||
|
||||
/* now it's time to get the parser */
|
||||
mp3type = gst_type_find_by_mime("audio/mpeg");
|
||||
factories = gst_type_get_sinks(mp3type);
|
||||
if (factories != NULL)
|
||||
parsefactory = GST_ELEMENTFACTORY(factories->data);
|
||||
else {
|
||||
g_print("sorry, can't find anyone registered to sink 'mp3'\n");
|
||||
return 1;
|
||||
}
|
||||
parse = gst_elementfactory_create(parsefactory,"parser");
|
||||
if (parse == NULL) {
|
||||
g_print("sorry, couldn't create parser\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
audiosink = gst_audiosink_new("audiosink");
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(src),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(src));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
gst_element_get_pad(audiosink,"sink"));
|
||||
|
||||
|
||||
sleep(5); /* to let the network buffer fill a bit */
|
||||
while(1) {
|
||||
g_print("calling gst_httpsrc_push\n");
|
||||
gst_httpsrc_push(GST_SRC(src));
|
||||
}
|
||||
|
||||
gst_object_destroy(GST_OBJECT(audiosink));
|
||||
gst_object_destroy(GST_OBJECT(parse));
|
||||
gst_object_destroy(GST_OBJECT(src));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
80
test/spectrum.c
Normal file
80
test/spectrum.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
#include <gnome.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
void spectrum_chain(GstPad *pad,GstBuffer *buf);
|
||||
gboolean idle_func(gpointer data);
|
||||
|
||||
GtkWidget *drawingarea;
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *bin;
|
||||
GstElementFactory *srcfactory;
|
||||
GstElement *src;
|
||||
GstElementFactory *spectrumfactory;
|
||||
GstElement *spectrum;
|
||||
GstPad *spectrumpad;
|
||||
|
||||
GtkWidget *appwindow;
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load("libgstspectrum.so");
|
||||
gnome_init("Spectrum","0.0.1",argc,argv);
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
srcfactory = gst_elementfactory_find("audiosrc");
|
||||
spectrumfactory = gst_elementfactory_find("gstspectrum");
|
||||
|
||||
src = gst_elementfactory_create(srcfactory,"src");
|
||||
gtk_object_set(GTK_OBJECT(src),"bytes_per_read",(gulong)1024,NULL);
|
||||
spectrum = gst_elementfactory_create(spectrumfactory,"spectrum");
|
||||
gtk_object_set(GTK_OBJECT(spectrum),"width",256,NULL);
|
||||
|
||||
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(spectrum));
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(spectrum,"sink"));
|
||||
|
||||
spectrumpad = gst_pad_new("sink",GST_PAD_SINK);
|
||||
gst_pad_set_chain_function(spectrumpad,spectrum_chain);
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(spectrum,"src"),spectrumpad);
|
||||
|
||||
appwindow = gnome_app_new("spectrum","Spectrum");
|
||||
drawingarea = gtk_drawing_area_new();
|
||||
gtk_drawing_area_size(GTK_DRAWING_AREA(drawingarea),256,32);
|
||||
gnome_app_set_contents(GNOME_APP(appwindow),drawingarea);
|
||||
gtk_widget_show_all(appwindow);
|
||||
|
||||
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_RUNNING);
|
||||
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_PLAYING);
|
||||
|
||||
g_idle_add(idle_func,src);
|
||||
|
||||
gtk_main();
|
||||
}
|
||||
|
||||
|
||||
void spectrum_chain(GstPad *pad,GstBuffer *buf) {
|
||||
gint i,size;
|
||||
guchar *data = buf->data;
|
||||
|
||||
gdk_draw_rectangle(drawingarea->window,drawingarea->style->black_gc,
|
||||
TRUE,0,0,GST_BUFFER_SIZE(buf),25);
|
||||
for (i=0;i<GST_BUFFER_SIZE(buf);i++) {
|
||||
gdk_draw_rectangle(drawingarea->window,drawingarea->style->white_gc,
|
||||
TRUE,i,32-data[i],1,data[i]);
|
||||
}
|
||||
gst_buffer_unref(buf);
|
||||
}
|
||||
|
||||
gboolean idle_func(gpointer data) {
|
||||
gst_src_push(GST_SRC(data));
|
||||
return TRUE;
|
||||
}
|
75
test/states.c
Normal file
75
test/states.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstBin *bin,
|
||||
GstElement *src, *identity, *sink;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
src = gst_disksrc_new("fakesrc");
|
||||
gst_disksrc_set_filename(src,"demo.mp3");
|
||||
list_pads(src);
|
||||
|
||||
binf = gst_bin_new("binf");
|
||||
|
||||
filter1 = gst_fakefilter_new("filter1");
|
||||
list_pads(filter1);
|
||||
|
||||
filter2 = gst_fakefilter_new("filter2");
|
||||
list_pads(filter2);
|
||||
|
||||
sink = gst_fakesink_new("fakesink");
|
||||
list_pads(sink);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(bin),"object_added",
|
||||
GTK_SIGNAL_FUNC(added_child),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(binf),"object_added",
|
||||
GTK_SIGNAL_FUNC(added_child),NULL);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(binf),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(src),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(filter1),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(filter2),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(sink),"parent_set",
|
||||
GTK_SIGNAL_FUNC(added_parent),NULL);
|
||||
|
||||
/* add filter1 to the subbin */
|
||||
gst_bin_add(GST_BIN(binf),GST_ELEMENT(filter1));
|
||||
gst_bin_add(GST_BIN(binf),GST_ELEMENT(filter2));
|
||||
/* connect the two together */
|
||||
gst_pad_connect(gst_element_get_pad(filter1,"src"),
|
||||
gst_element_get_pad(filter2,"sink"));
|
||||
/* export the pads */
|
||||
gst_element_add_ghost_pad(binf,gst_element_get_pad(filter1,"sink"));
|
||||
gst_element_add_ghost_pad(binf,gst_element_get_pad(filter2,"src"));
|
||||
list_pads(binf);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(src));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(binf));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(sink));
|
||||
|
||||
/* connect src to binf */
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(binf,"sink"));
|
||||
/* connect binf to sink */
|
||||
gst_pad_connect(gst_element_get_pad(binf,"src"),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
gst_disksrc_push(GST_SRC(src));
|
||||
|
||||
gst_object_destroy(GST_OBJECT(src));
|
||||
gst_object_destroy(GST_OBJECT(filter1));
|
||||
gst_object_destroy(GST_OBJECT(filter2));
|
||||
gst_object_destroy(GST_OBJECT(binf));
|
||||
gst_object_destroy(GST_OBJECT(sink));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
69
test/teardown.c
Normal file
69
test/teardown.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
GstPipeline *teardown_create_pipeline() {
|
||||
GstPipeline *pipeline;
|
||||
GstElementFactory *srcfactory, *sinkfactory;
|
||||
GstElement *src, *sink;
|
||||
GstPad *srcpad, *sinkpad;
|
||||
|
||||
pipeline = gst_pipeline_new("pipeline");
|
||||
g_return_if_fail(pipeline != NULL);
|
||||
|
||||
srcfactory = gst_elementfactory_find("fakesrc");
|
||||
g_return_if_fail(srcfactory != NULL);
|
||||
sinkfactory = gst_elementfactory_find("fakesink");
|
||||
g_return_if_fail(sinkfactory != NULL);
|
||||
src = gst_elementfactory_create(srcfactory,"src");
|
||||
g_return_if_fail(src != NULL);
|
||||
sink = gst_elementfactory_create(sinkfactory,"sink");
|
||||
g_return_if_fail(sink != NULL);
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(sink));
|
||||
|
||||
srcpad = gst_element_get_pad(src,"src");
|
||||
g_return_if_fail(srcpad != NULL);
|
||||
sinkpad = gst_element_get_pad(sink,"sink");
|
||||
g_return_if_fail(srcpad != NULL);
|
||||
|
||||
gst_pad_connect(srcpad,sinkpad);
|
||||
|
||||
return GST_PIPELINE(pipeline);
|
||||
}
|
||||
|
||||
void teardown_destroy_pipeline(GstPipeline *pipeline) {
|
||||
gst_element_destroy(pipeline);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *pipeline, *src;
|
||||
int i,j,max = 1;
|
||||
long usage1,usage2;
|
||||
|
||||
// _gst_plugin_spew = TRUE;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
if (argc == 2)
|
||||
max = atoi(argv[1]);
|
||||
|
||||
usage1 = vmsize();
|
||||
for (i=0;i<max;i++) {
|
||||
pipeline = teardown_create_pipeline();
|
||||
src = gst_bin_get_by_name(GST_BIN(pipeline),"src");
|
||||
// g_print("got source %p, pushing",src);
|
||||
// for (j=0;j<max;j++) {
|
||||
// gst_src_push(GST_SRC(src));
|
||||
// g_print(".");
|
||||
// }
|
||||
// g_print("\n");
|
||||
teardown_destroy_pipeline(pipeline);
|
||||
}
|
||||
usage2 = vmsize();
|
||||
g_print("uses %d bytes\n",usage2-usage1);
|
||||
}
|
63
test/typefind.c
Normal file
63
test/typefind.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstType *mp3type;
|
||||
GList *factories;
|
||||
GstElement *src;
|
||||
GList *padlist;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
disksrc = gst_disksrc_new("disksrc");
|
||||
g_print("created disksrc\n");
|
||||
if (argc == 2)
|
||||
gst_disksrc_set_filename(disksrc,argv[1]);
|
||||
else
|
||||
gst_disksrc_set_filename(disksrc,"Thank_you_very_much.au");
|
||||
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
|
||||
|
||||
|
||||
/* now it's time to get the parser */
|
||||
autype = gst_type_get_by_mime("audio/au");
|
||||
factories = gst_type_get_sinks(autype);
|
||||
if (factories != NULL)
|
||||
parsefactory = GST_ELEMENTFACTORY(factories->data);
|
||||
else {
|
||||
g_print("sorry, can't find anyone registered to sink 'au'\n");
|
||||
return 1;
|
||||
}
|
||||
parse = gst_elementfactory_create(parsefactory,"parser");
|
||||
if (parse == NULL) {
|
||||
g_print("sorry, couldn't create parser\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
audiosink = gst_audiosink_new("audiosink");
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
gst_element_get_pad(audiosink,"sink"));
|
||||
|
||||
while(1)
|
||||
gst_disksrc_push(GST_SRC(disksrc));
|
||||
|
||||
gst_object_destroy(GST_OBJECT(audiosink));
|
||||
gst_object_destroy(GST_OBJECT(parse));
|
||||
gst_object_destroy(GST_OBJECT(disksrc));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
44
test/types.c
Normal file
44
test/types.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
GstTypeFactory testfactory = { "test/test", ".tst", NULL };
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
guint16 id;
|
||||
GstType *type;
|
||||
GstElementFactory *element;
|
||||
GList *types, *elements;
|
||||
|
||||
// _gst_plugin_spew = TRUE;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
// gst_plugin_load_all();
|
||||
gst_plugin_load("libgstparseau.so");
|
||||
gst_plugin_load("libgstparsewav.so");
|
||||
gst_plugin_load("libgstxa.so");
|
||||
gst_plugin_load("libstereo.so");
|
||||
gst_plugin_load("libvolume.so");
|
||||
gst_plugin_load("libsmoothwave.so");
|
||||
gst_plugin_load("libgstspectrum.so");
|
||||
gst_plugin_load("libsynaesthesia.so");
|
||||
gst_plugin_load("libvumeter.so");
|
||||
|
||||
id = gst_type_register(&testfactory);
|
||||
|
||||
types = gst_type_get_list();
|
||||
while (types) {
|
||||
type = (GstType *)types->data;
|
||||
g_print("%d: have type '%s'\n",type->id,type->mime);
|
||||
types = g_list_next(types);
|
||||
}
|
||||
|
||||
elements = gst_elementfactory_get_list();
|
||||
while (elements) {
|
||||
element = (GstElementFactory *)elements->data;
|
||||
g_print("%d: have elementfactory '%s': \"%s\"\n",element->type,
|
||||
element->name,element->details->longname);
|
||||
elements = g_list_next(elements);
|
||||
}
|
||||
}
|
72
test/w.c
Normal file
72
test/w.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
void eof(GstSrc *src) {
|
||||
g_print("have eof, quitting\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstType *autype;
|
||||
GList *factories;
|
||||
GstElementFactory *parsefactory;
|
||||
GstElement *bin, *disksrc, *parse, *audiosink;
|
||||
GList *padlist;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
disksrc = gst_disksrc_new("disksrc");
|
||||
g_print("created disksrc\n");
|
||||
if (argc == 2)
|
||||
gst_disksrc_set_filename(disksrc,argv[1]);
|
||||
else
|
||||
gst_disksrc_set_filename(disksrc,"futile.wav");
|
||||
// gst_disksrc_set_bytesperread(disksrc,32768);
|
||||
g_print("loaded file '%s'\n",gst_disksrc_get_filename(disksrc));
|
||||
|
||||
|
||||
/* now it's time to get the parser */
|
||||
autype = gst_type_get_by_mime("audio/wav");
|
||||
factories = gst_type_get_sinks(autype);
|
||||
if (factories != NULL)
|
||||
parsefactory = GST_ELEMENTFACTORY(factories->data);
|
||||
else {
|
||||
g_print("sorry, can't find anyone registered to sink 'wav'\n");
|
||||
return 1;
|
||||
}
|
||||
parse = gst_elementfactory_create(parsefactory,"parser");
|
||||
if (parse == NULL) {
|
||||
g_print("sorry, couldn't create parser\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
audiosink = gst_audiosink_new("audiosink");
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(disksrc),"eof",
|
||||
GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(disksrc));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(parse));
|
||||
gst_bin_add(GST_BIN(bin),GST_OBJECT(audiosink));
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(parse,"src"),
|
||||
gst_element_get_pad(audiosink,"sink"));
|
||||
|
||||
while(1) {
|
||||
g_print("\n");
|
||||
gst_disksrc_push(GST_SRC(disksrc));
|
||||
}
|
||||
|
||||
gst_object_destroy(GST_OBJECT(audiosink));
|
||||
gst_object_destroy(GST_OBJECT(parse));
|
||||
gst_object_destroy(GST_OBJECT(disksrc));
|
||||
gst_object_destroy(GST_OBJECT(bin));
|
||||
}
|
||||
|
60
test/wave.c
Normal file
60
test/wave.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include <gnome.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
extern gboolean _gst_plugin_spew;
|
||||
|
||||
gboolean idle_func(gpointer data);
|
||||
|
||||
GtkWidget *drawingarea;
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstElement *bin;
|
||||
GstElementFactory *srcfactory;
|
||||
GstElement *src;
|
||||
GstElementFactory *wavefactory;
|
||||
GstElement *wave;
|
||||
|
||||
GtkWidget *appwindow;
|
||||
|
||||
_gst_plugin_spew = TRUE;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load("libsmoothwave.so");
|
||||
gnome_init("Wave","0.0.1",argc,argv);
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
|
||||
srcfactory = gst_elementfactory_find("audiosrc");
|
||||
g_return_if_fail(srcfactory != NULL);
|
||||
wavefactory = gst_elementfactory_find("smoothwave");
|
||||
g_return_if_fail(wavefactory != NULL);
|
||||
|
||||
src = gst_elementfactory_create(srcfactory,"src");
|
||||
gtk_object_set(GTK_OBJECT(src),"bytes_per_read",(gulong)2048,NULL);
|
||||
wave = gst_elementfactory_create(wavefactory,"wave");
|
||||
gtk_object_set(GTK_OBJECT(wave),"width",256,"height",100,NULL);
|
||||
|
||||
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(bin),GST_ELEMENT(wave));
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(wave,"sink"));
|
||||
|
||||
appwindow = gnome_app_new("wave","Wave");
|
||||
drawingarea = gtk_drawing_area_new();
|
||||
gnome_app_set_contents(GNOME_APP(appwindow),gst_util_get_widget_arg(GTK_OBJECT(wave),"widget"));
|
||||
gtk_widget_show_all(appwindow);
|
||||
|
||||
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_RUNNING);
|
||||
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_PLAYING);
|
||||
|
||||
g_idle_add(idle_func,src);
|
||||
|
||||
gtk_main();
|
||||
}
|
||||
|
||||
gboolean idle_func(gpointer data) {
|
||||
gst_src_push(GST_SRC(data));
|
||||
return TRUE;
|
||||
}
|
6
test/xml/Makefile.am
Normal file
6
test/xml/Makefile.am
Normal file
|
@ -0,0 +1,6 @@
|
|||
bin_PROGRAMS = readreg createreg
|
||||
|
||||
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) $(XML_CFLAGS) -I$(top_srcdir)
|
||||
LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(XML_LIBS) $(top_srcdir)/gst/libgst.la
|
||||
|
||||
EXTRA_DIST = README registry.xml
|
62
test/xml/createreg.c
Normal file
62
test/xml/createreg.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include <glib.h>
|
||||
#include <gnome-xml/parser.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
typedef struct _GstRegistryPlugin GstRegistryPlugin;
|
||||
typedef struct _GstRegistryElement GstRegistryElement;
|
||||
|
||||
struct _GstRegistryPlugin {
|
||||
gchar *name;
|
||||
gchar *filename;
|
||||
};
|
||||
|
||||
struct _GstRegistryElement {
|
||||
GstRegistryPlugin *plugin;
|
||||
gchar *name;
|
||||
GstElementDetails details;
|
||||
};
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr tree, subtree;
|
||||
GList *plugins = NULL, *elements = NULL;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
doc = xmlNewDoc("1.0");
|
||||
doc->root = xmlNewDocNode(doc,NULL,"GST-PluginRegistry",NULL);
|
||||
plugins = gst_plugin_get_list();
|
||||
while (plugins) {
|
||||
GstPlugin *plugin = (GstPlugin *)plugins->data;
|
||||
tree = xmlNewChild(doc->root,NULL,"plugin",NULL);
|
||||
subtree = xmlNewChild(tree,NULL,"name",plugin->name);
|
||||
subtree = xmlNewChild(tree,NULL,"longname",plugin->longname);
|
||||
subtree = xmlNewChild(tree,NULL,"filename",plugin->filename);
|
||||
elements = plugin->elements;
|
||||
while (elements) {
|
||||
GstElementFactory *element = (GstElementFactory *)elements->data;
|
||||
tree = xmlNewChild(doc->root,NULL,"element",NULL);
|
||||
subtree = xmlNewChild(tree,NULL,"plugin",plugin->name);
|
||||
subtree = xmlNewChild(tree,NULL,"name",element->name);
|
||||
subtree = xmlNewChild(tree,NULL,"longname",
|
||||
element->details->longname);
|
||||
subtree = xmlNewChild(tree,NULL,"class",
|
||||
element->details->class);
|
||||
subtree = xmlNewChild(tree,NULL,"description",
|
||||
element->details->description);
|
||||
subtree = xmlNewChild(tree,NULL,"version",
|
||||
element->details->version);
|
||||
subtree = xmlNewChild(tree,NULL,"author",
|
||||
element->details->author);
|
||||
subtree = xmlNewChild(tree,NULL,"copyright",
|
||||
element->details->copyright);
|
||||
elements = g_list_next(elements);
|
||||
}
|
||||
plugins = g_list_next(plugins);
|
||||
}
|
||||
|
||||
xmlSaveFile("newreg.xml",doc);
|
||||
|
||||
exit(0);
|
||||
}
|
126
test/xml/readreg.c
Normal file
126
test/xml/readreg.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include <glib.h>
|
||||
#include <gnome-xml/parser.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
typedef struct _GstRegistryPlugin GstRegistryPlugin;
|
||||
typedef struct _GstRegistryElement GstRegistryElement;
|
||||
|
||||
struct _GstRegistryPlugin {
|
||||
gchar *name;
|
||||
gchar *filename;
|
||||
};
|
||||
|
||||
struct _GstRegistryElement {
|
||||
GstRegistryPlugin *plugin;
|
||||
gchar *name;
|
||||
GstElementDetails details;
|
||||
};
|
||||
|
||||
gchar *getcontents(xmlDocPtr doc,xmlNodePtr cur) {
|
||||
return g_strdup(xmlNodeListGetString(doc,cur->childs,1));
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr cur;
|
||||
int i;
|
||||
|
||||
GSList *plugins = NULL, *elements = NULL;
|
||||
|
||||
// gst_init(&argc,&argv);
|
||||
|
||||
doc = xmlParseFile("registry.xml");
|
||||
g_assert(doc != NULL);
|
||||
|
||||
cur = doc->root;
|
||||
if (cur == NULL) {
|
||||
g_print("registry is empty\n");
|
||||
xmlFreeDoc(doc);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (strcmp(cur->name,"GST-PluginRegistry")) {
|
||||
g_print("document not the right type\n");
|
||||
xmlFreeDoc(doc);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cur = cur->childs; /* 'childs'??? He (Daniel) is Dutch, so... */
|
||||
while (cur != NULL) {
|
||||
if (!strcmp(cur->name,"plugin")) {
|
||||
xmlNodePtr field = cur->childs;
|
||||
GstRegistryPlugin *plugin = g_new0(GstRegistryPlugin,1);
|
||||
|
||||
while (field) {
|
||||
if (!strcmp(field->name,"name"))
|
||||
plugin->name = getcontents(doc,field);
|
||||
else if (!strcmp(field->name,"filename"))
|
||||
plugin->filename = getcontents(doc,field);
|
||||
field = field->next;
|
||||
}
|
||||
g_print("new plugin '%s' at '%s'\n",plugin->name,plugin->filename);
|
||||
plugins = g_slist_prepend(plugins,plugin);
|
||||
} else if (!strcmp(cur->name,"element")) {
|
||||
xmlNodePtr field = cur->childs;
|
||||
GstRegistryElement *element = g_new0(GstRegistryElement,1);
|
||||
|
||||
while (field) {
|
||||
if (!strcmp(field->name,"plugin")) {
|
||||
gchar *pluginname = getcontents(doc,field);
|
||||
GSList *list = plugins;
|
||||
element->plugin = NULL;
|
||||
while (list) {
|
||||
GstRegistryPlugin *plugin = (GstRegistryPlugin *)list->data;
|
||||
if (!strcmp(pluginname,plugin->name)) {
|
||||
element->plugin = plugin;
|
||||
break;
|
||||
}
|
||||
list = g_slist_next(list);
|
||||
}
|
||||
} else if (!strcmp(field->name,"name"))
|
||||
element->name = getcontents(doc,field);
|
||||
else if (!strcmp(field->name,"longname"))
|
||||
element->details.longname = getcontents(doc,field);
|
||||
else if (!strcmp(field->name,"class"))
|
||||
element->details.class = getcontents(doc,field);
|
||||
else if (!strcmp(field->name,"description"))
|
||||
element->details.description = getcontents(doc,field);
|
||||
else if (!strcmp(field->name,"version"))
|
||||
element->details.version = getcontents(doc,field);
|
||||
else if (!strcmp(field->name,"author"))
|
||||
element->details.author = getcontents(doc,field);
|
||||
else if (!strcmp(field->name,"copyright"))
|
||||
element->details.copyright = getcontents(doc,field);
|
||||
field = field->next;
|
||||
}
|
||||
g_print("new element '%s'in '%s'\n",element->name,element->plugin->name);
|
||||
elements = g_slist_prepend(elements,element);
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
for (i=1;i<argc;i++) {
|
||||
GSList *list;
|
||||
g_print("searching for element '%s'\n",argv[i]);
|
||||
list = elements;
|
||||
while (list) {
|
||||
GstRegistryElement *element = (GstRegistryElement *)list->data;
|
||||
// g_print("comparing against '%s'\n",element->name);
|
||||
if (!strcmp(argv[i],element->name)) {
|
||||
g_print("Plugin name: %s\n",element->plugin->name);
|
||||
g_print("Plugin filename: %s\n",element->plugin->filename);
|
||||
g_print("Element name: %s\n",element->name);
|
||||
g_print("Element long name: %s\n",element->details.longname);
|
||||
g_print("Element class: %s\n",element->details.class);
|
||||
g_print("Element description: %s\n",element->details.description);
|
||||
g_print("Element version: %s\n",element->details.version);
|
||||
g_print("Element author: %s\n",element->details.author);
|
||||
g_print("Element copyright: %s\n",element->details.copyright);
|
||||
// gst_plugin_load_absolute(element->plugin->filename);
|
||||
}
|
||||
list = g_slist_next(list);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
4
tools/Makefile.am
Normal file
4
tools/Makefile.am
Normal file
|
@ -0,0 +1,4 @@
|
|||
bin_PROGRAMS = launch
|
||||
|
||||
LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la
|
||||
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) -I$(top_srcdir)
|
16
tools/README
Normal file
16
tools/README
Normal file
|
@ -0,0 +1,16 @@
|
|||
launch
|
||||
======
|
||||
|
||||
This is a tool that will construct pipelines based on a command-line
|
||||
syntax. The syntax is rather complex to enable all the features I want it
|
||||
to have, but should be easy to use for most people. Multi-pathed and
|
||||
feedback pipelines are the most complex.
|
||||
|
||||
A simple commandline looks like:
|
||||
|
||||
./launch disksrc demo.mp3 | mp3parse | mpg123 | audiosink-oss
|
||||
|
||||
A more complex pipeline looks like:
|
||||
|
||||
./launch disksrc redpill.vob | css-descramble | private_stream_1.0| \
|
||||
(ac3parse | ac3dec | audioink-oss) video_0| (mpeg2dec | videosink)
|
115
tools/launch.c
Normal file
115
tools/launch.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
typedef struct _launch_delayed_pad launch_delayed_pad;
|
||||
struct _launch_delayed_pad {
|
||||
gchar *name;
|
||||
GstPad *peer;
|
||||
};
|
||||
|
||||
void launch_newpad(GstElement *element,GstPad *pad,launch_delayed_pad *peer) {
|
||||
gst_info("have NEW_PAD signal\n");
|
||||
// if it matches, connect it
|
||||
if (!strcmp(gst_pad_get_name(pad),peer->name)) {
|
||||
gst_pad_connect(pad,peer->peer);
|
||||
gst_info("delayed connect of '%s' to '%s'\n",
|
||||
gst_pad_get_name(pad),gst_pad_get_name(peer->peer));
|
||||
}
|
||||
}
|
||||
|
||||
gint parse(int argc,char *argv[],GstElement *parent,gint offset,gchar endchar) {
|
||||
gint i = offset;
|
||||
gchar *plugin;
|
||||
GstElement *element, *prevelement;
|
||||
GstPad *prevpad,*nextpad;
|
||||
gchar *prevpadname = NULL,*nextpadname = NULL;
|
||||
gchar *ptr;
|
||||
gint len;
|
||||
launch_delayed_pad *delayed;
|
||||
|
||||
gst_info("at offset %d, argc is %d\n",i,argc);
|
||||
|
||||
// loop through all the arguments
|
||||
while (i < argc) {
|
||||
// first is the plugin name
|
||||
plugin = argv[i++];
|
||||
gst_info("plugin is \"%s\"\n",plugin);
|
||||
// record previous element
|
||||
prevelement = element;
|
||||
// create the element and add it to the parent
|
||||
element = gst_elementfactory_make(plugin,plugin);
|
||||
gst_bin_add(GST_BIN(parent),element);
|
||||
// connect it to the previous if there is one
|
||||
if (nextpadname != NULL) {
|
||||
// grab the pad of this element
|
||||
nextpad = gst_element_get_pad(element,nextpadname);
|
||||
g_return_if_fail(nextpad != NULL);
|
||||
// check to see if the pad exists yet, connect it if it does
|
||||
if (prevpad != NULL) {
|
||||
gst_pad_connect(prevpad,nextpad);
|
||||
gst_info("wired '%s' to '%s'\n",
|
||||
gst_pad_get_name(prevpad),gst_pad_get_name(nextpad));
|
||||
}
|
||||
// otherwise we have to attach and wait for it to show
|
||||
else {
|
||||
delayed = g_new0(launch_delayed_pad,1);
|
||||
delayed->name = prevpadname;
|
||||
delayed->peer = nextpad;
|
||||
gtk_signal_connect(GTK_OBJECT(prevelement),"new_pad",
|
||||
launch_newpad,delayed);
|
||||
}
|
||||
}
|
||||
// then come all the other things
|
||||
while (i < argc) {
|
||||
// snag the length in advance;
|
||||
len = strlen(argv[i]);
|
||||
// if it's just a connection, pick the 'src' pad and move on
|
||||
if (ptr = strchr(argv[i],'|')) {
|
||||
// if there's a previous pad name
|
||||
if (ptr != argv[i]) {
|
||||
ptr[0] = '\0';
|
||||
prevpadname = argv[i];
|
||||
prevpad = gst_element_get_pad(element,prevpadname);
|
||||
} else
|
||||
prevpad = gst_element_get_pad(element,"src");
|
||||
// if there's a next pad name
|
||||
if (((ptr - argv[i]) + 1) < len) {
|
||||
nextpadname = ptr + 1;
|
||||
} else
|
||||
nextpadname = "sink";
|
||||
i++;
|
||||
break;
|
||||
} else {
|
||||
gst_info("have unknown argument '%s'\n",argv[i]);
|
||||
gtk_object_set(GTK_OBJECT(element),"location",argv[i],NULL);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
int t;
|
||||
GstElement *pipeline;
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gst_plugin_load_all();
|
||||
|
||||
gst_info("\n\n");
|
||||
|
||||
pipeline = gst_elementfactory_make("thread","launch");
|
||||
if (t = atoi(argv[1]))
|
||||
parse(argc,argv,pipeline,2,0);
|
||||
else
|
||||
parse(argc,argv,pipeline,1,0);
|
||||
|
||||
xmlSaveFile("launch.xml",gst_xml_write(pipeline));
|
||||
|
||||
gst_element_set_state(pipeline,GST_STATE_RUNNING);
|
||||
gst_element_set_state(pipeline,GST_STATE_PLAYING);
|
||||
|
||||
if (t)
|
||||
sleep(t);
|
||||
else
|
||||
sleep(5);
|
||||
}
|
Loading…
Reference in a new issue