[gst-devel] Docs/RFC: GstData

David I. Lehn dlehn at vt.edu
Thu Apr 18 01:16:03 CEST 2002


* Benjamin Otte <in7y118 at public.uni-hamburg.de> [20020416 20:11]:
> Hierarchy
> ---------
> GstData
>   GstInstream
>     GstBuffer
>     GstEventNewMedia
...
>   GstOutOfStream
>     GstEventLock
...

Hmm.  GstInstream and GstOutOfStream seem rather awkward names.   I'll
second the idea that they might not be needed.  What's the difference in
the code between those two classes?  Is there any code in them at all?
You could do something like the following:

GstData
  GstEvent
    GstBuffer
    GstEventEOS
    GstEvent...
    ... the rest ...

and then just add a method to GstEvent:

  gboolean gst_event_is_inline(GstEvent *);

and let subclasses override it (or set a flag if we're lazy since these
are not real objects anyway) to specify if they are inline (instream) or
out of band (OutOfStream).  (or whatever naming would be)


> GstData
> =======
> 
> typedef GstData * (*GstDataCopyFunction) (GstData *data);
> typedef void (*GstDataFreeFunction) (GstData *data);
> 
> struct _GstData
> {
>   /* inheritance */
>   GstDataClass *	klass;

Eh?  This doesn't really inherit from a class, it is an instance of a
class.  Maybe use /* isa */.


> struct _GstDataClass
> {
>   GstDataType		type;
> 
>   GstDataCopyFunction	copy;
>   GstDataFreeFunction	free;
> };
> 

What is GstDataType?  Is that going to be related to the GType system?
It would be nice to also make sure all these pseudo-classes are
registered as boxed types too.


> If it can be a parent class, it should implement these three functions
> publically:
> void gst_my_data_init (GstData *data) {
>   /* call the parent's init function, eg: */
>   gst_data_init (data);
>   /* initialize your data now */
> }

I think methods should use their own class with this sort of style:

void gst_mt_data_init (GstMyData *data) {
   gst_data_init (GST_DATA (data));
   ...
}

similar in your other code.


> If GstMyData should be instantiable, you should do this:
> Get a class struct, something like this:
> static GstDataClass my_data_class = { GST_TYPE_MY_DATA,
>       gst_my_data_copy_func,
>       gst_my_data_free_func };
> FIXME: At the moment all types need to be specified in a big enum in
> gstdata.h.
>        We might want to change that when we support event plugins.
> The two functions above should look something like this:
> GstData *gst_my_data_copy_func (GstData *from) {
>   /* allocate memory */
>   GstMyData *copy = g_new (GstData, 1);
>   /* copy relevant variables or initialize them */
>   gst_my_data_copy (copy, from);
> 
>   return copy;
> }

do you mean g_new (GstMyData, 1)?


> void gst_my_data_free_func (GstData *data) {
>   /* first dispose all data */
>   gst_my_data_dispose (data);
>   /* now free the struct */
>   g_free (data);
> }
> 
> Now you just need a function that can be called from the real world:
> GstMyData *gst_my_data_new (void) {
>   /* allocate memory */
>   GstMyData *my_data = g_new (GstData, 1);

again, do you mean g_new (GstMyData, 1)?


>   /* initialize the variables */
>   gst_my_data_init (GST_DATA (my_data));

again, I think methods can use their own types:
  gst_my_data_init (GstMyData *data) {}
so we can simplify call to:
  gst_my_data_init (my_data);

so then this casting makes more sense:

>   /* set the right type */
>   GST_DATA (my_data)->type = &my_data_class;
> 
>   return my_data;
> }
...
> MT safety
> ---------
> Manipulating data inside an object is not threadsafe unless otherwise
> noted.
> If an object has a reference count of 1 it is assumed that the reference
> holder is the only user of that object and he may modify it the way he
> likes.
> If the reference count is greater than 1, the object may not be modified.
> If you need to modify it, you have to copy the object and use that copy
> instead.
> NB: Object creation and refcounting are threadsafe - or must be
> implemented that way.
> 

Are there locks for this?  How do know if someone has called _ref() on
your object between checking the refcount and accessing the object data?


> GBoxed
> ------

yeah, do setup boxed types.  things like python bindings will need it to
pass around thes structs anyway.  better to have it in core than
repeated in other binding packages too.


> GstInstream
> ===========
> 
> GstInstream is the base class for events and buffers that are passed
> inside the stream.
> It enhances the GstData struct by
> guint64		offset[GST_OFFSET_TYPES];
> This field describes the offset in the current stream in various different
> ways:
> GST_OFFSET_BYTES:  The number of bytes from the beginning of the stream.
> GST_OFFSET_TIME:   The timestamp in microseconds. The beginning of the
> stream equals timestamp 0. In buffers the timestamp should match the
> beginning of the data.
> GST_OFFSET_FRAMES: This type is specific to the stream and should be
> defined there. (video will probably use it for frame numbers, audio to
> count samples)
> If an offset can't be specified, it is set to GST_OFFSET_INVALID, which
> equals (guint64) -1. The byte offset always has to be specified. It is an
> error if it is invalid.
> A plugin playing data from an "infinite" source (eg a shoutcast stream
> from the internet) it should start with byteoffset 0.
> 

At first look this seems a bit complex and messy.  Maybe it's the best
way though... I dunno.  Are those fields likely to be all filled for
common cases?   Or, for instance, would a filesrc set the bytes, a
demuxer set the time, and a decoder set the frame as data flows along a
pipeline?

What if an app need some other type of tag?  Like fields or some other
block number or whatever.  Maybe plan for arbitrary tagged data by
making these fields opaque and use accessor functions to get/set them.

_INVALID seems more like an error condition than lack-of-value.  Perhaps
_NONE or _UNKNOWN or _UNSET or something.

I'm not sure about the guint64 array either.  I'll make another post
to start time handling discussion.


> GstEventNewMedia
> ----------------
> Signals the start of a new stream. This must be send before any buffer of
> a new stream can be send.

Why not call it GstEventNewStream?
(I'd suggest BOS to match EOS but that would be confusing <g>)


> GstEventDiscontinuous
> ---------------------
> This must be send between buffers, that don't have continuous data. This
> is necessary for example after seeking or when data is dropped for speed.
> 

Speaking of QoS.  We probably need a whole lot of work to do that
properly.  Could get messy and involve quality negotiation algorithm to
query pipelines for elements that can most appropriately drop quality to
improve performance based on some criteria... hmm.


> GstEventLength
> --------------
> Specifies the length of the stream.
> FIXME: Write more, when sure how to do this.
> 

How is this used?  My first thought is that apps should just query a
size parameter in the source element.  Doesn't seem the sort of thing
that need to travel in the stream.  But maybe there's a good use...

I hope I didn't tear up your work too much. ;)

-dave
-- 
David I. Lehn <dlehn at vt.edu>  | http://crib.lehn.org:8080/~dlehn/
Computer Engineering Graduate @ Virginia Tech in sunny Blacksburg, VA




More information about the gstreamer-devel mailing list