mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
Merge branch 'master' into 0.11
This commit is contained in:
commit
0894ed2053
11 changed files with 206 additions and 36 deletions
|
@ -5,22 +5,22 @@ This document describes the design and use cases for the progress reporting
|
||||||
messages.
|
messages.
|
||||||
|
|
||||||
PROGRESS messages are posted on the bus to inform the application about the
|
PROGRESS messages are posted on the bus to inform the application about the
|
||||||
progress of asynchonous operations in the pipeline. This should not be confused
|
progress of asynchronous operations in the pipeline. This should not be confused
|
||||||
with asynchronous state changes.
|
with asynchronous state changes.
|
||||||
|
|
||||||
We accomodate for the following requirements:
|
We accommodate for the following requirements:
|
||||||
|
|
||||||
- Application is informed when an async operation starts and completes.
|
- Application is informed when an async operation starts and completes.
|
||||||
- It should be possible for the application to generically detect common
|
- It should be possible for the application to generically detect common
|
||||||
operations and incorporate their progress into the GUI.
|
operations and incorporate their progress into the GUI.
|
||||||
- Applications can cancel pending operations by doing regular state changes.
|
- Applications can cancel pending operations by doing regular state changes.
|
||||||
- Applications should be abe able to wait for completion of async operations.
|
- Applications should be able to wait for completion of async operations.
|
||||||
|
|
||||||
We allow for the following scenarios:
|
We allow for the following scenarios:
|
||||||
|
|
||||||
- Elements want to inform the application about asynchronous DNS lookups and
|
- Elements want to inform the application about asynchronous DNS lookups and
|
||||||
pending network requests. This includes starting and completing the lookup.
|
pending network requests. This includes starting and completing the lookup.
|
||||||
- Elements opening devices and resources assynchronously.
|
- Elements opening devices and resources asynchronously.
|
||||||
- Applications having more freedom to implement timeout and cancelation of
|
- Applications having more freedom to implement timeout and cancelation of
|
||||||
operations that currently block the state changes or happen invisibly behind
|
operations that currently block the state changes or happen invisibly behind
|
||||||
the scenes.
|
the scenes.
|
||||||
|
@ -29,9 +29,9 @@ We allow for the following scenarios:
|
||||||
Rationale
|
Rationale
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
The main reason for adding these extra progress notifications is twofold:
|
The main reason for adding these extra progress notifications is twofold:
|
||||||
|
|
||||||
1) to give the application more information of what is going on
|
1) to give the application more information of what is going on
|
||||||
|
|
||||||
When there are well defined progress information codes, applications
|
When there are well defined progress information codes, applications
|
||||||
can let the user know about the status of the progress. We anticipate to
|
can let the user know about the status of the progress. We anticipate to
|
||||||
|
@ -48,7 +48,7 @@ The main reason for adding these extra progress notifications is twofold:
|
||||||
We would like to make the state change function, instead, start a separate
|
We would like to make the state change function, instead, start a separate
|
||||||
thread that performs the blocking operations in a cancelable way. When going
|
thread that performs the blocking operations in a cancelable way. When going
|
||||||
back to the NULL state, all pending operations would be canceled immediately.
|
back to the NULL state, all pending operations would be canceled immediately.
|
||||||
|
|
||||||
For downward state changes, we want to let the application implement its own
|
For downward state changes, we want to let the application implement its own
|
||||||
timeout mechanism. For example: when stopping an RTSP stream, the clients
|
timeout mechanism. For example: when stopping an RTSP stream, the clients
|
||||||
needs to send a TEARDOWN request to the server. This can however take an
|
needs to send a TEARDOWN request to the server. This can however take an
|
||||||
|
@ -66,7 +66,7 @@ Async state changes
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
GStreamer currently has a GST_STATE_CHANGE_ASYNC return value to note to the
|
GStreamer currently has a GST_STATE_CHANGE_ASYNC return value to note to the
|
||||||
application that a state change is happening assynchronously.
|
application that a state change is happening asynchronously.
|
||||||
|
|
||||||
The main purpose of this return value is to make the pipeline wait for preroll
|
The main purpose of this return value is to make the pipeline wait for preroll
|
||||||
and delay a future (upwards) state changes until the sinks are prerolled.
|
and delay a future (upwards) state changes until the sinks are prerolled.
|
||||||
|
@ -74,34 +74,35 @@ and delay a future (upwards) state changes until the sinks are prerolled.
|
||||||
In the case of async operations on source, this will automatically force sinks
|
In the case of async operations on source, this will automatically force sinks
|
||||||
to stay async because they will not preroll before the source can produce data.
|
to stay async because they will not preroll before the source can produce data.
|
||||||
|
|
||||||
The fact that other asynchonous operations happen behind the scnes is irrelevant
|
The fact that other asynchronous operations happen behind the scenes is
|
||||||
for the prerolling process so it is not implemented with the ASYNC state change
|
irrelevant for the prerolling process so it is not implemented with the ASYNC
|
||||||
return value in order to not complicate the state changes and mix concepts.
|
state change return value in order to not complicate the state changes and mix
|
||||||
|
concepts.
|
||||||
|
|
||||||
|
|
||||||
Use cases
|
Use cases
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
* RTSP client (but also HTTP, MMS, ...)
|
* RTSP client (but also HTTP, MMS, ...)
|
||||||
|
|
||||||
When the client goes from the READY to the PAUSED state, it opens a socket,
|
When the client goes from the READY to the PAUSED state, it opens a socket,
|
||||||
performs a DNS lookup, retieves the SDP and negotiates the streams. All these
|
performs a DNS lookup, retrieves the SDP and negotiates the streams. All these
|
||||||
operations currently block the state change function for an undefinite amount
|
operations currently block the state change function for an indefinite amount
|
||||||
of time and while they are blocking cannot be canceled.
|
of time and while they are blocking cannot be canceled.
|
||||||
|
|
||||||
Instead, a thread would be started to perform these operations assynchronously
|
Instead, a thread would be started to perform these operations asynchronously
|
||||||
and the state change would complete with the usual NO_PREROLL return value.
|
and the state change would complete with the usual NO_PREROLL return value.
|
||||||
Before starting the thread a PROGRESS message would be posted to mark the
|
Before starting the thread a PROGRESS message would be posted to mark the
|
||||||
start of the async operation.
|
start of the async operation.
|
||||||
|
|
||||||
As the DNS lookup completes and the connection is established, PROGRESS messages
|
As the DNS lookup completes and the connection is established, PROGRESS
|
||||||
are posted on the bus to inform the application of the progress. When
|
messages are posted on the bus to inform the application of the progress. When
|
||||||
something fails, an error is posted and a PROGRESS CANCELED message is posted.
|
something fails, an error is posted and a PROGRESS CANCELED message is posted.
|
||||||
The application can then stop the pipeline.
|
The application can then stop the pipeline.
|
||||||
|
|
||||||
If there are no errors and the setup of the streams completed successfully, a
|
If there are no errors and the setup of the streams completed successfully, a
|
||||||
PROGRESS COMPLETED is posted on the bus. The thread then goes to sleep and the
|
PROGRESS COMPLETED is posted on the bus. The thread then goes to sleep and the
|
||||||
assynchronous operation completed.
|
asynchronous operation completed.
|
||||||
|
|
||||||
The RTSP protocol requires to send a TEARDOWN request to the server
|
The RTSP protocol requires to send a TEARDOWN request to the server
|
||||||
before closing the connection and destroying the socket. A state change to the
|
before closing the connection and destroying the socket. A state change to the
|
||||||
|
@ -117,7 +118,7 @@ Use cases
|
||||||
|
|
||||||
DNS lookup and connection times can be measured by calculating the elapsed
|
DNS lookup and connection times can be measured by calculating the elapsed
|
||||||
time between the various PROGRESS messages.
|
time between the various PROGRESS messages.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Messages
|
Messages
|
||||||
|
@ -212,7 +213,7 @@ Categories
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
We want to propose some standard codes here:
|
We want to propose some standard codes here:
|
||||||
|
|
||||||
"open" : A resource is being opened
|
"open" : A resource is being opened
|
||||||
"close" : A resource is being closed
|
"close" : A resource is being closed
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,8 @@ gst_atomic_queue_new (guint initial_size)
|
||||||
* @queue: a #GstAtomicQueue
|
* @queue: a #GstAtomicQueue
|
||||||
*
|
*
|
||||||
* Increase the refcount of @queue.
|
* Increase the refcount of @queue.
|
||||||
|
*
|
||||||
|
* Since: 0.10.33
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_atomic_queue_ref (GstAtomicQueue * queue)
|
gst_atomic_queue_ref (GstAtomicQueue * queue)
|
||||||
|
@ -195,6 +197,8 @@ gst_atomic_queue_free (GstAtomicQueue * queue)
|
||||||
* @queue: a #GstAtomicQueue
|
* @queue: a #GstAtomicQueue
|
||||||
*
|
*
|
||||||
* Unref @queue and free the memory when the refcount reaches 0.
|
* Unref @queue and free the memory when the refcount reaches 0.
|
||||||
|
*
|
||||||
|
* Since: 0.10.33
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_atomic_queue_unref (GstAtomicQueue * queue)
|
gst_atomic_queue_unref (GstAtomicQueue * queue)
|
||||||
|
@ -212,6 +216,8 @@ gst_atomic_queue_unref (GstAtomicQueue * queue)
|
||||||
* Peek the head element of the queue without removing it from the queue.
|
* Peek the head element of the queue without removing it from the queue.
|
||||||
*
|
*
|
||||||
* Returns: the head element of @queue or NULL when the queue is empty.
|
* Returns: the head element of @queue or NULL when the queue is empty.
|
||||||
|
*
|
||||||
|
* Since: 0.10.33
|
||||||
*/
|
*/
|
||||||
gpointer
|
gpointer
|
||||||
gst_atomic_queue_peek (GstAtomicQueue * queue)
|
gst_atomic_queue_peek (GstAtomicQueue * queue)
|
||||||
|
@ -261,6 +267,8 @@ gst_atomic_queue_peek (GstAtomicQueue * queue)
|
||||||
* Get the head element of the queue.
|
* Get the head element of the queue.
|
||||||
*
|
*
|
||||||
* Returns: the head element of @queue or NULL when the queue is empty.
|
* Returns: the head element of @queue or NULL when the queue is empty.
|
||||||
|
*
|
||||||
|
* Since: 0.10.33
|
||||||
*/
|
*/
|
||||||
gpointer
|
gpointer
|
||||||
gst_atomic_queue_pop (GstAtomicQueue * queue)
|
gst_atomic_queue_pop (GstAtomicQueue * queue)
|
||||||
|
@ -326,6 +334,8 @@ gst_atomic_queue_pop (GstAtomicQueue * queue)
|
||||||
* @data: the data
|
* @data: the data
|
||||||
*
|
*
|
||||||
* Append @data to the tail of the queue.
|
* Append @data to the tail of the queue.
|
||||||
|
*
|
||||||
|
* Since: 0.10.33
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_atomic_queue_push (GstAtomicQueue * queue, gpointer data)
|
gst_atomic_queue_push (GstAtomicQueue * queue, gpointer data)
|
||||||
|
@ -378,6 +388,8 @@ gst_atomic_queue_push (GstAtomicQueue * queue, gpointer data)
|
||||||
* Get the amount of items in the queue.
|
* Get the amount of items in the queue.
|
||||||
*
|
*
|
||||||
* Returns: the number of elements in the queue.
|
* Returns: the number of elements in the queue.
|
||||||
|
*
|
||||||
|
* Since: 0.10.33
|
||||||
*/
|
*/
|
||||||
guint
|
guint
|
||||||
gst_atomic_queue_length (GstAtomicQueue * queue)
|
gst_atomic_queue_length (GstAtomicQueue * queue)
|
||||||
|
|
|
@ -32,6 +32,8 @@ G_BEGIN_DECLS
|
||||||
* Opaque atomic data queue.
|
* Opaque atomic data queue.
|
||||||
*
|
*
|
||||||
* Use the acessor functions to get the stored values.
|
* Use the acessor functions to get the stored values.
|
||||||
|
*
|
||||||
|
* Since: 0.10.33
|
||||||
*/
|
*/
|
||||||
typedef struct _GstAtomicQueue GstAtomicQueue;
|
typedef struct _GstAtomicQueue GstAtomicQueue;
|
||||||
|
|
||||||
|
|
|
@ -217,12 +217,14 @@ typedef struct _GstBufferClass GstBufferClass;
|
||||||
* @GST_BUFFER_FLAG_MEDIA1: a flag whose use is specific to the caps of the buffer. Since: 0.10.23.
|
* @GST_BUFFER_FLAG_MEDIA1: a flag whose use is specific to the caps of the buffer. Since: 0.10.23.
|
||||||
* @GST_BUFFER_FLAG_MEDIA2: a flag whose use is specific to the caps of the buffer. Since: 0.10.23.
|
* @GST_BUFFER_FLAG_MEDIA2: a flag whose use is specific to the caps of the buffer. Since: 0.10.23.
|
||||||
* @GST_BUFFER_FLAG_MEDIA3: a flag whose use is specific to the caps of the buffer. Since: 0.10.23.
|
* @GST_BUFFER_FLAG_MEDIA3: a flag whose use is specific to the caps of the buffer. Since: 0.10.23.
|
||||||
|
* @GST_BUFFER_FLAG_MEDIA4: a flag whose use is specific to the caps of the buffer. Since: 0.10.33.
|
||||||
* @GST_BUFFER_FLAG_LAST: additional flags can be added starting from this flag.
|
* @GST_BUFFER_FLAG_LAST: additional flags can be added starting from this flag.
|
||||||
*
|
*
|
||||||
* A set of buffer flags used to describe properties of a #GstBuffer.
|
* A set of buffer flags used to describe properties of a #GstBuffer.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_BUFFER_FLAG_READONLY = GST_MINI_OBJECT_FLAG_READONLY,
|
GST_BUFFER_FLAG_READONLY = GST_MINI_OBJECT_FLAG_READONLY,
|
||||||
|
GST_BUFFER_FLAG_MEDIA4 = GST_MINI_OBJECT_FLAG_RESERVED1,
|
||||||
GST_BUFFER_FLAG_PREROLL = (GST_MINI_OBJECT_FLAG_LAST << 0),
|
GST_BUFFER_FLAG_PREROLL = (GST_MINI_OBJECT_FLAG_LAST << 0),
|
||||||
GST_BUFFER_FLAG_DISCONT = (GST_MINI_OBJECT_FLAG_LAST << 1),
|
GST_BUFFER_FLAG_DISCONT = (GST_MINI_OBJECT_FLAG_LAST << 1),
|
||||||
GST_BUFFER_FLAG_IN_CAPS = (GST_MINI_OBJECT_FLAG_LAST << 2),
|
GST_BUFFER_FLAG_IN_CAPS = (GST_MINI_OBJECT_FLAG_LAST << 2),
|
||||||
|
|
|
@ -27,9 +27,33 @@
|
||||||
*
|
*
|
||||||
* GstIndex is used to generate a stream index of one or more elements
|
* GstIndex is used to generate a stream index of one or more elements
|
||||||
* in a pipeline.
|
* in a pipeline.
|
||||||
|
*
|
||||||
|
* Elements will overload the set_index and get_index virtual methods in
|
||||||
|
* #GstElement. When streaming data, the element will add index entries if it
|
||||||
|
* has an index set.
|
||||||
|
*
|
||||||
|
* Each element that adds to the index will do that using a writer_id. The
|
||||||
|
* writer_id is obtained from gst_index_get_writer_id().
|
||||||
|
*
|
||||||
|
* The application that wants to index the stream will create a new index object
|
||||||
|
* using gst_index_new() or gst_index_factory_make(). The index is assigned to a
|
||||||
|
* specific element, a bin or the whole pipeline. This will cause indexable
|
||||||
|
* elements to add entires to the index while playing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* FIXME: complete gobject annotations */
|
/* FIXME: complete gobject annotations */
|
||||||
|
/* FIXME-0.11: cleanup API
|
||||||
|
* - no one seems to use GstIndexGroup, GstIndexCertainty
|
||||||
|
*
|
||||||
|
* - the API for application to use the index is mostly missing
|
||||||
|
* - apps need to get a list of writers
|
||||||
|
* - apps need to be able to iterate over each writers index entry collection
|
||||||
|
* - gst_index_get_assoc_entry() should pass ownership
|
||||||
|
* - the GstIndexEntry structure is large and contains repetitive information
|
||||||
|
* - we want to allow Indexers to implement a saner storage and create
|
||||||
|
* GstIndexEntries on demand (the app has to free them), might even make
|
||||||
|
* sense to ask the app to provide a ptr and fill it.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "gst_private.h"
|
#include "gst_private.h"
|
||||||
|
|
||||||
|
@ -281,7 +305,9 @@ gst_index_group_free (GstIndexGroup * group)
|
||||||
/**
|
/**
|
||||||
* gst_index_new:
|
* gst_index_new:
|
||||||
*
|
*
|
||||||
* Create a new tileindex object
|
* Create a new dummy index object. Use gst_element_set_index() to assign that
|
||||||
|
* to an element or pipeline. This index is not storing anything, but will
|
||||||
|
* still emit e.g. the #GstIndex::entry-added signal.
|
||||||
*
|
*
|
||||||
* Returns: (transfer full): a new index object
|
* Returns: (transfer full): a new index object
|
||||||
*/
|
*/
|
||||||
|
@ -633,20 +659,23 @@ gst_index_gtype_resolver (GstIndex * index, GstObject * writer,
|
||||||
g_return_val_if_fail (writer != NULL, FALSE);
|
g_return_val_if_fail (writer != NULL, FALSE);
|
||||||
|
|
||||||
if (GST_IS_PAD (writer)) {
|
if (GST_IS_PAD (writer)) {
|
||||||
GstElement *element =
|
GstObject *element = gst_object_get_parent (GST_OBJECT (writer));
|
||||||
(GstElement *) gst_object_get_parent (GST_OBJECT (writer));
|
|
||||||
gchar *name;
|
gchar *name;
|
||||||
|
|
||||||
name = gst_object_get_name (writer);
|
name = gst_object_get_name (writer);
|
||||||
*writer_string = g_strdup_printf ("%s.%s",
|
if (element) {
|
||||||
g_type_name (G_OBJECT_TYPE (element)), name);
|
*writer_string = g_strdup_printf ("%s.%s",
|
||||||
|
G_OBJECT_TYPE_NAME (element), name);
|
||||||
|
gst_object_unref (element);
|
||||||
|
} else {
|
||||||
|
*writer_string = name;
|
||||||
|
name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
gst_object_unref (element);
|
|
||||||
g_free (name);
|
g_free (name);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
*writer_string =
|
*writer_string = g_strdup (G_OBJECT_TYPE_NAME (writer));
|
||||||
g_strdup_printf ("%s", g_type_name (G_OBJECT_TYPE (writer)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
|
@ -105,14 +105,17 @@ typedef void (*GstMiniObjectFinalizeFunction) (GstMiniObject *obj);
|
||||||
/**
|
/**
|
||||||
* GstMiniObjectFlags:
|
* GstMiniObjectFlags:
|
||||||
* @GST_MINI_OBJECT_FLAG_READONLY: is the miniobject readonly or writable
|
* @GST_MINI_OBJECT_FLAG_READONLY: is the miniobject readonly or writable
|
||||||
|
* @GST_MINI_OBJECT_FLAG_RESERVED1: a flag reserved for internal use e.g. as
|
||||||
|
* GST_BUFFER_FLAG_MEDIA4. Since: 0.10.33.
|
||||||
* @GST_MINI_OBJECT_FLAG_LAST: first flag that can be used by subclasses.
|
* @GST_MINI_OBJECT_FLAG_LAST: first flag that can be used by subclasses.
|
||||||
*
|
*
|
||||||
* Flags for the padtemplate
|
* Flags for the mini object
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
GST_MINI_OBJECT_FLAG_READONLY = (1<<0),
|
GST_MINI_OBJECT_FLAG_READONLY = (1<<0),
|
||||||
|
GST_MINI_OBJECT_FLAG_RESERVED1 = (1<<1),
|
||||||
/* padding */
|
/* padding */
|
||||||
GST_MINI_OBJECT_FLAG_LAST = (1<<4)
|
GST_MINI_OBJECT_FLAG_LAST = (1<<4)
|
||||||
} GstMiniObjectFlags;
|
} GstMiniObjectFlags;
|
||||||
|
|
|
@ -2017,6 +2017,12 @@ CREATE_USERIALIZATION (uint, UINT);
|
||||||
CREATE_USERIALIZATION (uint64, UINT64);
|
CREATE_USERIALIZATION (uint64, UINT64);
|
||||||
CREATE_USERIALIZATION (ulong, ULONG);
|
CREATE_USERIALIZATION (ulong, ULONG);
|
||||||
|
|
||||||
|
/* FIXME 0.11: remove this again, plugins shouldn't have uchar properties */
|
||||||
|
#ifndef G_MAXUCHAR
|
||||||
|
#define G_MAXUCHAR 255
|
||||||
|
#endif
|
||||||
|
CREATE_USERIALIZATION (uchar, UCHAR);
|
||||||
|
|
||||||
/**********
|
/**********
|
||||||
* double *
|
* double *
|
||||||
**********/
|
**********/
|
||||||
|
@ -4931,6 +4937,8 @@ _gst_value_initialize (void)
|
||||||
REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
|
REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
|
||||||
REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
|
REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
|
||||||
|
|
||||||
|
REGISTER_SERIALIZATION (G_TYPE_UCHAR, uchar);
|
||||||
|
|
||||||
g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
|
g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
|
||||||
gst_value_transform_fourcc_string);
|
gst_value_transform_fourcc_string);
|
||||||
g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
|
g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
|
||||||
|
|
|
@ -248,6 +248,27 @@ struct _GstBaseTransformPrivate
|
||||||
gboolean proxy_alloc;
|
gboolean proxy_alloc;
|
||||||
GstCaps *sink_alloc;
|
GstCaps *sink_alloc;
|
||||||
GstCaps *src_alloc;
|
GstCaps *src_alloc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This flag controls if basetransform should explicitly
|
||||||
|
* do a pad alloc when it receives a buffer even if it operates on
|
||||||
|
* passthrough, this is needed to check for downstream caps suggestions
|
||||||
|
* and this newly alloc'ed buffer is discarded.
|
||||||
|
*
|
||||||
|
* Without this flag basetransform would try a pad alloc whenever it
|
||||||
|
* gets a new buffer and pipelines like:
|
||||||
|
* "src ! basetrans1 ! basetrans2 ! basetrans3 ! sink"
|
||||||
|
* Would have a 3 pad allocs for each buffer pushed downstream from the src.
|
||||||
|
*
|
||||||
|
* This flag is set to TRUE on start up, on setcaps and when a buffer is
|
||||||
|
* pushed downstream. It is set to FALSE after a pad alloc has been requested
|
||||||
|
* downstream.
|
||||||
|
* The rationale is that when a pad alloc flows through the pipeline, all
|
||||||
|
* basetransform elements on passthrough will avoid pad alloc'ing when they
|
||||||
|
* get the buffer.
|
||||||
|
*/
|
||||||
|
gboolean force_alloc;
|
||||||
|
|
||||||
/* upstream caps and size suggestions */
|
/* upstream caps and size suggestions */
|
||||||
GstCaps *sink_suggest;
|
GstCaps *sink_suggest;
|
||||||
guint size_suggest;
|
guint size_suggest;
|
||||||
|
@ -456,6 +477,7 @@ gst_base_transform_init (GstBaseTransform * trans,
|
||||||
|
|
||||||
trans->priv->processed = 0;
|
trans->priv->processed = 0;
|
||||||
trans->priv->dropped = 0;
|
trans->priv->dropped = 0;
|
||||||
|
trans->priv->force_alloc = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* given @caps on the src or sink pad (given by @direction)
|
/* given @caps on the src or sink pad (given by @direction)
|
||||||
|
@ -1167,6 +1189,8 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
/* new caps, force alloc on next buffer on the chain */
|
||||||
|
trans->priv->force_alloc = TRUE;
|
||||||
if (otherpeer)
|
if (otherpeer)
|
||||||
gst_object_unref (otherpeer);
|
gst_object_unref (otherpeer);
|
||||||
if (othercaps)
|
if (othercaps)
|
||||||
|
@ -1383,12 +1407,18 @@ gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
|
||||||
goto alloc_failed;
|
goto alloc_failed;
|
||||||
|
|
||||||
if (*out_buf == NULL) {
|
if (*out_buf == NULL) {
|
||||||
GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT, oldcaps);
|
if (trans->passthrough && !trans->priv->force_alloc) {
|
||||||
|
GST_DEBUG_OBJECT (trans, "Avoiding pad alloc");
|
||||||
|
*out_buf = gst_buffer_ref (in_buf);
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT,
|
||||||
|
oldcaps);
|
||||||
|
|
||||||
ret = gst_pad_alloc_buffer (trans->srcpad,
|
ret = gst_pad_alloc_buffer (trans->srcpad,
|
||||||
GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
|
GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
goto alloc_failed;
|
goto alloc_failed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* must always have a buffer by now */
|
/* must always have a buffer by now */
|
||||||
|
@ -1928,6 +1958,13 @@ gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
|
||||||
if (sink_suggest)
|
if (sink_suggest)
|
||||||
gst_caps_unref (sink_suggest);
|
gst_caps_unref (sink_suggest);
|
||||||
|
|
||||||
|
if (res == GST_FLOW_OK) {
|
||||||
|
/* just alloc'ed a buffer, so we only want to do this again if we
|
||||||
|
* received a buffer */
|
||||||
|
GST_DEBUG_OBJECT (trans, "Cleaning force alloc");
|
||||||
|
trans->priv->force_alloc = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -2256,6 +2293,9 @@ skip:
|
||||||
if (*outbuf != inbuf)
|
if (*outbuf != inbuf)
|
||||||
gst_buffer_unref (inbuf);
|
gst_buffer_unref (inbuf);
|
||||||
|
|
||||||
|
/* pushed a buffer, we can now try an alloc */
|
||||||
|
GST_DEBUG_OBJECT (trans, "Pushed a buffer, setting force alloc to true");
|
||||||
|
trans->priv->force_alloc = TRUE;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -2476,6 +2516,7 @@ gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
|
||||||
gst_caps_replace (&trans->priv->sink_suggest, NULL);
|
gst_caps_replace (&trans->priv->sink_suggest, NULL);
|
||||||
trans->priv->processed = 0;
|
trans->priv->processed = 0;
|
||||||
trans->priv->dropped = 0;
|
trans->priv->dropped = 0;
|
||||||
|
trans->priv->force_alloc = TRUE;
|
||||||
|
|
||||||
GST_OBJECT_UNLOCK (trans);
|
GST_OBJECT_UNLOCK (trans);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
#include "gstfakesink.h"
|
#include "gstfakesink.h"
|
||||||
#include <gst/gstmarshal.h>
|
#include <gst/gstmarshal.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -480,6 +481,7 @@ gst_fake_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
|
|
||||||
if (!sink->silent) {
|
if (!sink->silent) {
|
||||||
gchar ts_str[64], dur_str[64];
|
gchar ts_str[64], dur_str[64];
|
||||||
|
gchar flag_str[100];
|
||||||
|
|
||||||
GST_OBJECT_LOCK (sink);
|
GST_OBJECT_LOCK (sink);
|
||||||
g_free (sink->last_message);
|
g_free (sink->last_message);
|
||||||
|
@ -498,12 +500,32 @@ gst_fake_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
g_strlcpy (dur_str, "none", sizeof (dur_str));
|
g_strlcpy (dur_str, "none", sizeof (dur_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *flag_list[12] = {
|
||||||
|
"ro", "media4", "", "",
|
||||||
|
"preroll", "discont", "incaps", "gap",
|
||||||
|
"delta_unit", "media1", "media2", "media3"
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
char *end = flag_str;
|
||||||
|
end[0] = '\0';
|
||||||
|
for (i = 0; i < 12; i++) {
|
||||||
|
if (GST_MINI_OBJECT_CAST (buf)->flags & (1 << i)) {
|
||||||
|
strcpy (end, flag_list[i]);
|
||||||
|
end += strlen (end);
|
||||||
|
end[0] = ' ';
|
||||||
|
end[1] = '\0';
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sink->last_message =
|
sink->last_message =
|
||||||
g_strdup_printf ("chain ******* < (%5d bytes, timestamp: %s"
|
g_strdup_printf ("chain ******* < (%5d bytes, timestamp: %s"
|
||||||
", duration: %s, offset: %" G_GINT64_FORMAT ", offset_end: %"
|
", duration: %s, offset: %" G_GINT64_FORMAT ", offset_end: %"
|
||||||
G_GINT64_FORMAT ", flags: %d) %p", GST_BUFFER_SIZE (buf), ts_str,
|
G_GINT64_FORMAT ", flags: %d %s) %p", GST_BUFFER_SIZE (buf), ts_str,
|
||||||
dur_str, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf),
|
dur_str, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf),
|
||||||
GST_MINI_OBJECT_CAST (buf)->flags, buf);
|
GST_MINI_OBJECT_CAST (buf)->flags, flag_str, buf);
|
||||||
GST_OBJECT_UNLOCK (sink);
|
GST_OBJECT_UNLOCK (sink);
|
||||||
|
|
||||||
gst_fake_sink_notify_last_message (sink);
|
gst_fake_sink_notify_last_message (sink);
|
||||||
|
|
|
@ -245,6 +245,51 @@ GST_START_TEST (test_deserialize_guint64)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_deserialize_guchar)
|
||||||
|
{
|
||||||
|
GValue value = { 0 };
|
||||||
|
const char *strings[] = {
|
||||||
|
"0xff",
|
||||||
|
"255",
|
||||||
|
"-1",
|
||||||
|
"1",
|
||||||
|
"-0",
|
||||||
|
};
|
||||||
|
guchar results[] = {
|
||||||
|
0xff,
|
||||||
|
255,
|
||||||
|
(guchar) - 1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_value_init (&value, G_TYPE_UCHAR);
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (strings); ++i) {
|
||||||
|
fail_unless (gst_value_deserialize (&value, strings[i]),
|
||||||
|
"could not deserialize %s (%d)", strings[i], i);
|
||||||
|
fail_unless (g_value_get_uchar (&value) == results[i],
|
||||||
|
"resulting value is %u not %u, for string %s (%d)",
|
||||||
|
g_value_get_uchar (&value), results[i], strings[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test serialisation as well while we're at it */
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
GValue value = { 0 };
|
||||||
|
g_value_init (&value, G_TYPE_UCHAR);
|
||||||
|
|
||||||
|
g_value_set_uchar (&value, 255);
|
||||||
|
str = gst_value_serialize (&value);
|
||||||
|
|
||||||
|
fail_unless_equals_string (str, "255");
|
||||||
|
g_free (str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
GST_START_TEST (test_deserialize_gstfraction)
|
GST_START_TEST (test_deserialize_gstfraction)
|
||||||
{
|
{
|
||||||
GValue value = { 0 };
|
GValue value = { 0 };
|
||||||
|
@ -2565,6 +2610,7 @@ gst_value_suite (void)
|
||||||
tcase_add_test (tc_chain, test_deserialize_guint_failures);
|
tcase_add_test (tc_chain, test_deserialize_guint_failures);
|
||||||
tcase_add_test (tc_chain, test_deserialize_gint64);
|
tcase_add_test (tc_chain, test_deserialize_gint64);
|
||||||
tcase_add_test (tc_chain, test_deserialize_guint64);
|
tcase_add_test (tc_chain, test_deserialize_guint64);
|
||||||
|
tcase_add_test (tc_chain, test_deserialize_guchar);
|
||||||
tcase_add_test (tc_chain, test_deserialize_gstfraction);
|
tcase_add_test (tc_chain, test_deserialize_gstfraction);
|
||||||
tcase_add_test (tc_chain, test_serialize_flags);
|
tcase_add_test (tc_chain, test_serialize_flags);
|
||||||
tcase_add_test (tc_chain, test_deserialize_flags);
|
tcase_add_test (tc_chain, test_deserialize_flags);
|
||||||
|
|
|
@ -1191,6 +1191,10 @@ GST_START_TEST (basetransform_chain_ct3)
|
||||||
fail_unless (res == GST_FLOW_OK);
|
fail_unless (res == GST_FLOW_OK);
|
||||||
fail_if (buffer == NULL);
|
fail_if (buffer == NULL);
|
||||||
fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (buffer), incaps));
|
fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (buffer), incaps));
|
||||||
|
/* if we don't push here, basetransform will think it doesn't need do a
|
||||||
|
* pad alloc for downstream caps suggestions */
|
||||||
|
res = gst_test_trans_push (trans, buffer);
|
||||||
|
buffer = gst_test_trans_pop (trans);
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
/* FIXME should not call the pad-alloc function but it currently does */
|
/* FIXME should not call the pad-alloc function but it currently does */
|
||||||
fail_unless (buffer_alloc_ct2_called == FALSE);
|
fail_unless (buffer_alloc_ct2_called == FALSE);
|
||||||
|
|
Loading…
Reference in a new issue