Commit 9ef1346b authored by Wim Taymans's avatar Wim Taymans

context: use context on buffers instead of caps

Put the srcpad context on buffers instead of caps. This allows us to associate
all the relevant info contained in events with a buffer.
parent 9136abf6
......@@ -670,6 +670,7 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
_gst_query_initialize ();
_gst_caps_initialize ();
_gst_meta_init ();
gst_context_get_type ();
g_type_class_ref (gst_object_get_type ());
g_type_class_ref (gst_pad_get_type ());
......
......@@ -306,10 +306,6 @@ gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
}
}
if (flags & GST_BUFFER_COPY_CAPS) {
gst_caps_replace (&GST_BUFFER_CAPS (dest), GST_BUFFER_CAPS (src));
}
if (flags & GST_BUFFER_COPY_MEMORY) {
GstMemory *mem;
gsize skip, left, len, i, bsize;
......@@ -402,7 +398,7 @@ _gst_buffer_free (GstBuffer * buffer)
GST_CAT_LOG (GST_CAT_BUFFER, "finalize %p", buffer);
gst_caps_replace (&GST_BUFFER_CAPS (buffer), NULL);
gst_context_replace (&GST_BUFFER_CONTEXT (buffer), NULL);
/* free metadata */
for (walk = GST_BUFFER_META (buffer); walk; walk = next) {
......@@ -444,7 +440,7 @@ gst_buffer_init (GstBufferImpl * buffer, gsize size)
(GstMiniObjectFreeFunction) _gst_buffer_free;
GST_BUFFER (buffer)->pool = NULL;
GST_BUFFER_CAPS (buffer) = NULL;
GST_BUFFER_CONTEXT (buffer) = NULL;
GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
......@@ -1057,71 +1053,65 @@ gst_buffer_memcmp (GstBuffer * buffer, gsize offset, gconstpointer mem,
}
/**
* gst_buffer_get_caps:
* gst_buffer_get_context:
* @buffer: a #GstBuffer.
*
* Gets the media type of the buffer. This can be NULL if there
* is no media type attached to this buffer.
* Gets the context of the buffer. This can be NULL if there
* is no context attached to this buffer.
*
* Returns: (transfer full): a reference to the #GstCaps. unref after usage.
* Returns NULL if there were no caps on this buffer.
* Returns: (transfer full): a reference to the #GstContext. unref after usage.
* Returns NULL if there was no context on this buffer.
*/
/* this is not made atomic because if the buffer were reffed from multiple
* threads, it would have a refcount > 2 and thus be immutable.
*/
GstCaps *
gst_buffer_get_caps (GstBuffer * buffer)
GstContext *
gst_buffer_get_context (GstBuffer * buffer)
{
GstCaps *ret;
GstContext *ret;
g_return_val_if_fail (buffer != NULL, NULL);
ret = GST_BUFFER_CAPS (buffer);
ret = GST_BUFFER_CONTEXT (buffer);
if (ret)
gst_caps_ref (ret);
gst_context_ref (ret);
return ret;
}
/**
* gst_buffer_set_caps:
* gst_buffer_set_context:
* @buffer: a #GstBuffer.
* @caps: (transfer none): a #GstCaps.
* @context: (transfer none): a #GstContext.
*
* Sets the media type on the buffer. The refcount of the caps will
* be increased and any previous caps on the buffer will be
* Sets the media type on the buffer. The refcount of the context will
* be increased and any previous context on the buffer will be
* unreffed.
*/
/* this is not made atomic because if the buffer were reffed from multiple
* threads, it would have a refcount > 2 and thus be immutable.
*/
void
gst_buffer_set_caps (GstBuffer * buffer, GstCaps * caps)
gst_buffer_set_context (GstBuffer * buffer, GstContext * context)
{
g_return_if_fail (buffer != NULL);
g_return_if_fail (caps == NULL || GST_CAPS_IS_SIMPLE (caps));
#if GST_VERSION_NANO == 1
/* we enable this extra debugging in git versions only for now */
g_warn_if_fail (gst_buffer_is_writable (buffer));
/* FIXME: would be nice to also check if caps are fixed here, but expensive */
#endif
g_return_if_fail (gst_buffer_is_writable (buffer));
gst_caps_replace (&GST_BUFFER_CAPS (buffer), caps);
gst_context_replace (&GST_BUFFER_CONTEXT (buffer), context);
}
/**
* gst_buffer_copy_region:
* @parent: a #GstBuffer.
* @offset: the offset into parent #GstBuffer at which the new sub-buffer
* @offset: the offset into parent #GstBuffer at which the new sub-buffer
* begins.
* @size: the size of the new #GstBuffer sub-buffer, in bytes.
*
* Creates a sub-buffer from @parent at @offset and @size.
* This sub-buffer uses the actual memory space of the parent buffer.
* This function will copy the offset and timestamp fields when the
* offset is 0. If not, they will be set to #GST_CLOCK_TIME_NONE and
* offset is 0. If not, they will be set to #GST_CLOCK_TIME_NONE and
* #GST_BUFFER_OFFSET_NONE.
* If @offset equals 0 and @size equals the total size of @buffer, the
* duration and offset end fields are also copied. If not they will be set
......@@ -1509,3 +1499,22 @@ gst_buffer_iterate_meta (GstBuffer * buffer, gpointer * state)
else
return NULL;
}
GstCaps *
gst_buffer_caps (GstBuffer * buffer)
{
GstContext *context;
GstEvent *event;
GstCaps *caps = NULL;
if (!(context = GST_BUFFER_CONTEXT (buffer)))
return NULL;
if (!(event = gst_context_get (context, GST_EVENT_CAPS)))
return NULL;
gst_event_parse_caps (event, &caps);
gst_event_unref (event);
return caps;
}
......@@ -24,18 +24,18 @@
#ifndef __GST_BUFFER_H__
#define __GST_BUFFER_H__
typedef struct _GstBuffer GstBuffer;
typedef struct _GstBufferPool GstBufferPool;
#include <gst/gstminiobject.h>
#include <gst/gstclock.h>
#include <gst/gstcaps.h>
#include <gst/gstcontext.h>
#include <gst/gstmemory.h>
G_BEGIN_DECLS
extern GType _gst_buffer_type;
typedef struct _GstBuffer GstBuffer;
typedef struct _GstBufferPool GstBufferPool;
/**
* GST_BUFFER_TRACE_NAME:
*
......@@ -112,12 +112,12 @@ typedef struct _GstBufferPool GstBufferPool;
*/
#define GST_BUFFER_DURATION(buf) (GST_BUFFER_CAST(buf)->duration)
/**
* GST_BUFFER_CAPS:
* GST_BUFFER_CONTEXT:
* @buf: a #GstBuffer.
*
* The caps for this buffer.
* The context for this buffer.
*/
#define GST_BUFFER_CAPS(buf) (GST_BUFFER_CAST(buf)->caps)
#define GST_BUFFER_CONTEXT(buf) (GST_BUFFER_CAST(buf)->context)
/**
* GST_BUFFER_OFFSET:
* @buf: a #GstBuffer.
......@@ -260,7 +260,7 @@ struct _GstBuffer {
/*< public >*/ /* with COW */
GstBufferPool *pool;
/* the media type of this buffer */
GstCaps *caps;
GstContext *context;
/* timestamp */
GstClockTime timestamp;
......@@ -386,7 +386,6 @@ gst_buffer_copy (const GstBuffer * buf)
* @GST_BUFFER_COPY_FLAGS: flag indicating that buffer flags should be copied
* @GST_BUFFER_COPY_TIMESTAMPS: flag indicating that buffer timestamp, duration,
* offset and offset_end should be copied
* @GST_BUFFER_COPY_CAPS: flag indicating that buffer caps should be copied
* @GST_BUFFER_COPY_MEMORY: flag indicating that buffer memory should be copied
* and appended to already existing memory
* @GST_BUFFER_COPY_MERGE: flag indicating that buffer memory should be
......@@ -399,7 +398,6 @@ typedef enum {
GST_BUFFER_COPY_NONE = 0,
GST_BUFFER_COPY_FLAGS = (1 << 0),
GST_BUFFER_COPY_TIMESTAMPS = (1 << 1),
GST_BUFFER_COPY_CAPS = (1 << 2),
GST_BUFFER_COPY_MEMORY = (1 << 3),
GST_BUFFER_COPY_MERGE = (1 << 4)
} GstBufferCopyFlags;
......@@ -410,7 +408,7 @@ typedef enum {
* Combination of all possible metadata fields that can be copied with
* gst_buffer_copy_into().
*/
#define GST_BUFFER_COPY_METADATA (GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_CAPS)
#define GST_BUFFER_COPY_METADATA (GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS)
/**
* GST_BUFFER_COPY_ALL:
......@@ -469,8 +467,8 @@ G_STMT_START { \
GST_MINI_OBJECT_CAST (nbuf)); \
} G_STMT_END
GstCaps* gst_buffer_get_caps (GstBuffer *buffer);
void gst_buffer_set_caps (GstBuffer *buffer, GstCaps *caps);
GstContext* gst_buffer_get_context (GstBuffer *buffer);
void gst_buffer_set_context (GstBuffer *buffer, GstContext *context);
/* creating a region */
GstBuffer* gst_buffer_copy_region (GstBuffer *parent, GstBufferCopyFlags flags,
......@@ -518,6 +516,9 @@ GstMeta * gst_buffer_iterate_meta (GstBuffer *buffer, gpointer *st
*/
#define gst_value_get_buffer(v) GST_BUFFER_CAST (g_value_get_boxed(v))
/* shortcuts */
GstCaps * gst_buffer_caps (GstBuffer *buffer);
G_END_DECLS
#endif /* __GST_BUFFER_H__ */
......@@ -60,11 +60,11 @@ gst_context_get_type (void)
static void
_gst_context_free (GstContext * context)
{
GST_LOG ("freeing context %p", context);
g_return_if_fail (context != NULL);
g_return_if_fail (GST_IS_CONTEXT (context));
GST_LOG ("freeing context %p", context);
gst_context_clear (context);
g_slice_free1 (GST_MINI_OBJECT_SIZE (context), context);
......@@ -181,3 +181,22 @@ gst_context_clear (GstContext * context)
for (i = 0; i < GST_EVENT_MAX_STICKY; i++)
gst_event_replace (&context->events[i], NULL);
}
/**
* gst_context_foreach:
* @context: a #GstContext
* @func: a #GFunc
* @user_data: user data
*
* Call @func with the non NULL event and @user_data.
*/
void
gst_context_foreach (GstContext * context, GFunc func, gpointer user_data)
{
guint i;
GstEvent *event;
for (i = 0; i < GST_EVENT_MAX_STICKY; i++)
if ((event = context->events[i]))
func (event, user_data);
}
......@@ -23,6 +23,8 @@
#ifndef __GST_CONTEXT_H__
#define __GST_CONTEXT_H__
typedef struct _GstContext GstContext;
#include <gst/gstminiobject.h>
#include <gst/gstevent.h>
......@@ -30,7 +32,6 @@ G_BEGIN_DECLS
#define GST_CONTEXT_TRACE_NAME "GstContext"
typedef struct _GstContext GstContext;
#define GST_TYPE_CONTEXT (gst_context_get_type())
#define GST_IS_CONTEXT(obj) (GST_IS_MINI_OBJECT_TYPE (obj, GST_TYPE_CONTEXT))
......@@ -134,11 +135,15 @@ gst_context_copy (const GstContext * context)
GstContext * gst_context_new (void);
/* updating and setting events */
void gst_context_update (GstContext *context, GstEvent *event);
GstEvent * gst_context_get (GstContext *context, GstEventType type);
void gst_context_clear (GstContext *context);
/* foreach */
void gst_context_foreach (GstContext *context, GFunc func, gpointer user_data);
G_END_DECLS
#endif /* __GST_CONTEXT_H__ */
......@@ -25,10 +25,13 @@
#ifndef __GST_EVENT_H__
#define __GST_EVENT_H__
typedef struct _GstEvent GstEvent;
#include <gst/gstminiobject.h>
#include <gst/gstformat.h>
#include <gst/gstobject.h>
#include <gst/gstclock.h>
#include <gst/gstcaps.h>
#include <gst/gststructure.h>
#include <gst/gsttaglist.h>
......@@ -167,8 +170,6 @@ typedef enum {
*/
#define GST_EVENT_TRACE_NAME "GstEvent"
typedef struct _GstEvent GstEvent;
#define GST_TYPE_EVENT (gst_event_get_type())
#define GST_IS_EVENT(obj) (GST_IS_MINI_OBJECT_TYPE (obj, GST_TYPE_EVENT))
#define GST_EVENT(obj) ((GstEvent *)(obj))
......
......@@ -623,6 +623,8 @@ gst_ghost_pad_do_unlink (GstPad * pad)
static void
on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
{
/* FIXME, add new signal for notifying when the context caps change */
#if 0
GstCaps *caps;
gboolean changed;
......@@ -646,11 +648,14 @@ on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
if (caps)
gst_caps_unref (caps);
#endif
}
static void
on_src_target_notify (GstPad * target, GParamSpec * unused, gpointer user_data)
{
/* FIXME, add new signal for notifying when the context caps change */
#if 0
GstProxyPad *proxypad;
GstGhostPad *gpad;
GstCaps *caps;
......@@ -702,6 +707,7 @@ on_src_target_notify (GstPad * target, GParamSpec * unused, gpointer user_data)
done:
if (caps)
gst_caps_unref (caps);
#endif
}
static gboolean
......
......@@ -100,7 +100,6 @@ typedef struct _GstPadPushCache GstPadPushCache;
struct _GstPadPushCache
{
GstPad *peer; /* reffed peer pad */
GstCaps *caps; /* caps for this link */
};
static GstPadPushCache _pad_cache_invalid = { NULL, };
......@@ -371,8 +370,6 @@ gst_pad_init (GstPad * pad)
g_static_rec_mutex_init (pad->stream_rec_lock);
pad->block_cond = g_cond_new ();
pad->context = gst_context_new ();
}
static void
......@@ -406,7 +403,10 @@ gst_pad_dispose (GObject * object)
pad->block_data = NULL;
}
gst_context_clear (pad->context);
if (GST_PAD_CONTEXT (pad))
gst_context_replace (&GST_PAD_CONTEXT (pad), NULL);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
......@@ -434,8 +434,6 @@ gst_pad_finalize (GObject * object)
pad->block_cond = NULL;
}
gst_context_unref (pad->context);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
......@@ -620,7 +618,8 @@ post_activate (GstPad * pad, GstActivateMode new_mode)
/* ensures that streaming stops */
GST_PAD_STREAM_LOCK (pad);
GST_DEBUG_OBJECT (pad, "stopped streaming");
gst_context_clear (pad->context);
if (pad->context)
gst_context_clear (pad->context);
GST_PAD_STREAM_UNLOCK (pad);
break;
}
......@@ -2605,52 +2604,42 @@ could_not_set:
}
}
static gboolean
gst_pad_configure_sink (GstPad * pad, GstCaps * caps)
typedef struct
{
gboolean res;
/* See if pad accepts the caps */
if (!gst_caps_can_intersect (caps, gst_pad_get_pad_template_caps (pad)))
goto not_accepted;
/* set caps on pad if call succeeds */
res = gst_pad_set_caps (pad, caps);
/* no need to unref the caps here, set_caps takes a ref and
* our ref goes away when we leave this function. */
return res;
GstPadEventFunction eventfunc;
GstPad *pad;
GstFlowReturn ret;
} ContextData;
not_accepted:
{
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"caps %" GST_PTR_FORMAT " not accepted", caps);
return FALSE;
}
static void
context_func (GstEvent * event, ContextData * data)
{
data->eventfunc (data->pad, gst_event_ref (event));
/* FIXME, update return value when we can */
}
/* returns TRUE if the src pad could be configured to accept the given caps */
static gboolean
gst_pad_configure_src (GstPad * pad, GstCaps * caps, gboolean dosetcaps)
static GstFlowReturn
gst_pad_configure_sink (GstPad * pad, GstContext * context)
{
gboolean res;
ContextData data;
if (dosetcaps) {
/* See if pad accepts the caps */
if (!gst_pad_accept_caps (pad, caps))
goto not_accepted;
if (G_UNLIKELY ((data.eventfunc = GST_PAD_EVENTFUNC (pad)) == NULL))
goto no_function;
res = gst_pad_set_caps (pad, caps);
} else {
res = TRUE;
}
return res;
data.ret = GST_FLOW_OK;
data.pad = pad;
gst_context_foreach (context, (GFunc) context_func, &data);
/* set context on pad if all succeeds */
gst_context_replace (&GST_PAD_CONTEXT (pad), context);
return data.ret;
not_accepted:
no_function:
{
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"caps %" GST_PTR_FORMAT " not accepted", caps);
return FALSE;
g_warning ("pad %s:%s has no event handler, file a bug.",
GST_DEBUG_PAD_NAME (pad));
return GST_FLOW_ERROR;
}
}
......@@ -3407,22 +3396,22 @@ gst_pad_data_unref (gboolean is_buffer, void *data)
}
}
static GstCaps *
gst_pad_data_get_caps (gboolean is_buffer, void *data)
static GstContext *
gst_pad_data_get_context (gboolean is_buffer, void *data)
{
GstCaps *caps;
GstContext *context;
if (G_LIKELY (is_buffer)) {
caps = GST_BUFFER_CAPS (data);
context = GST_BUFFER_CONTEXT (data);
} else {
GstBuffer *buf;
if ((buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (data), 0)))
caps = GST_BUFFER_CAPS (buf);
context = GST_BUFFER_CONTEXT (buf);
else
caps = NULL;
context = NULL;
}
return caps;
return context;
}
/* this is the chain function that does not perform the additional argument
......@@ -3430,10 +3419,9 @@ gst_pad_data_get_caps (gboolean is_buffer, void *data)
*/
static inline GstFlowReturn
gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data,
GstPadPushCache * cache)
GstContext * context, GstPadPushCache * cache)
{
GstCaps *caps;
gboolean caps_changed;
gboolean context_changed;
GstFlowReturn ret;
gboolean emit_signal;
......@@ -3443,44 +3431,8 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data,
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
caps = gst_pad_data_get_caps (is_buffer, data);
caps_changed = caps && caps != GST_PAD_CAPS (pad);
context_changed = context && context != GST_PAD_CONTEXT (pad);
emit_signal = GST_PAD_DO_BUFFER_SIGNALS (pad) > 0;
#if 0
if (G_UNLIKELY (GST_PAD_IS_STICKY_PENDING (pad))) {
GstPadEventFunction eventfunc;
if (G_LIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)))) {
GstEvent *events[GST_EVENT_MAX_STICKY];
GstEvent *event;
guint i;
/* need to make a copy because when we release the object lock, things
* could just change */
for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
if ((event = pad->sticky[i]))
events[i] = gst_event_ref (event);
else
events[i] = NULL;
}
/* clear the flag */
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_STICKY_PENDING);
GST_OBJECT_UNLOCK (pad);
/* and push */
GST_DEBUG_OBJECT (pad, "pushing sticky events");
for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
if ((event = events[i]))
eventfunc (pad, event);
}
/* and restart, we released the lock things might have changed */
goto again;
}
}
#endif
GST_OBJECT_UNLOCK (pad);
/* see if the signal should be emited, we emit before caps nego as
......@@ -3498,9 +3450,9 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data,
}
/* we got a new datatype on the pad, see if it can handle it */
if (G_UNLIKELY (caps_changed)) {
GST_DEBUG_OBJECT (pad, "caps changed to %p %" GST_PTR_FORMAT, caps, caps);
if (G_UNLIKELY (!gst_pad_configure_sink (pad, caps)))
if (G_UNLIKELY (context_changed)) {
GST_DEBUG_OBJECT (pad, "context changed to %p", context);
if (G_UNLIKELY (gst_pad_configure_sink (pad, context) != GST_FLOW_OK))
goto not_negotiated;
}
......@@ -3521,7 +3473,6 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data,
if (cache) {
cache->peer = gst_object_ref (pad);
cache->caps = caps ? gst_caps_ref (caps) : NULL;
}
ret = chainfunc (pad, GST_BUFFER_CAST (data));
......@@ -3565,9 +3516,10 @@ chain_groups:
for (i = 0; i < len; i++) {
buffer = gst_buffer_list_get (list, i);
context = GST_BUFFER_CONTEXT (buffer);
ret =
gst_pad_chain_data_unchecked (pad, TRUE, gst_buffer_ref (buffer),
NULL);
context, NULL);
if (ret != GST_FLOW_OK)
break;
}
......@@ -3648,7 +3600,8 @@ gst_pad_chain (GstPad * pad, GstBuffer * buffer)
g_return_val_if_fail (GST_PAD_IS_SINK (pad), GST_FLOW_ERROR);
g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
return gst_pad_chain_data_unchecked (pad, TRUE, buffer, NULL);
return gst_pad_chain_data_unchecked (pad, TRUE, buffer,
GST_BUFFER_CONTEXT (buffer), NULL);
}
/**
......@@ -3687,17 +3640,17 @@ gst_pad_chain_list (GstPad * pad, GstBufferList * list)
g_return_val_if_fail (GST_PAD_IS_SINK (pad), GST_FLOW_ERROR);
g_return_val_if_fail (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR);
return gst_pad_chain_data_unchecked (pad, FALSE, list, NULL);
return gst_pad_chain_data_unchecked (pad, FALSE, list,
gst_pad_data_get_context (FALSE, list), NULL);
}
static GstFlowReturn
gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data,
GstPadPushCache * cache)
GstContext * context, GstPadPushCache * cache)
{
GstPad *peer;
GstFlowReturn ret;
GstCaps *caps;
gboolean caps_changed;
gboolean context_changed;
GST_OBJECT_LOCK (pad);
......@@ -3729,25 +3682,25 @@ gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data,
if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
goto not_linked;
/* Before pushing the buffer to the peer pad, ensure that caps
* are set on this pad */
caps = gst_pad_data_get_caps (is_buffer, data);
caps_changed = caps && caps != GST_PAD_CAPS (pad);
/* Before pushing the buffer to the peer pad, ensure that context
* is set on the buffer */
context_changed = context != GST_PAD_CONTEXT (pad);
/* take ref to peer pad before releasing the lock */
gst_object_ref (peer);
GST_OBJECT_UNLOCK (pad);
/* we got a new datatype from the pad, it had better handle it */