mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 15:08:53 +00:00
rtpbasedepayload: Fixed HdrExt handling for aggregated output buffer
If a depayloader aggregates multiple RTP buffers into one buffer only the last RTP buffer was checked for header extensions. Now the depayloader remembers all RTP packets pushed before a output buffer is pushed and checks all RTP buffers for header extensions. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4979>
This commit is contained in:
parent
62f09513e5
commit
d086491909
5 changed files with 634 additions and 8 deletions
|
@ -2332,7 +2332,39 @@ audio codec</doc>
|
||||||
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbaseaudiopayload.h"/>
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbaseaudiopayload.h"/>
|
||||||
</record>
|
</record>
|
||||||
<class name="RTPBaseDepayload" c:symbol-prefix="rtp_base_depayload" c:type="GstRTPBaseDepayload" parent="Gst.Element" abstract="1" glib:type-name="GstRTPBaseDepayload" glib:get-type="gst_rtp_base_depayload_get_type" glib:type-struct="RTPBaseDepayloadClass">
|
<class name="RTPBaseDepayload" c:symbol-prefix="rtp_base_depayload" c:type="GstRTPBaseDepayload" parent="Gst.Element" abstract="1" glib:type-name="GstRTPBaseDepayload" glib:get-type="gst_rtp_base_depayload_get_type" glib:type-struct="RTPBaseDepayloadClass">
|
||||||
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Provides a base class for RTP depayloaders</doc>
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Provides a base class for RTP depayloaders
|
||||||
|
|
||||||
|
In order to handle RTP header extensions correctly if the
|
||||||
|
depayloader aggregates multiple RTP packet payloads into one output
|
||||||
|
buffer this class provides the function
|
||||||
|
gst_rtp_base_depayload_set_aggregate_hdrext_enabled(). If the
|
||||||
|
aggregation is enabled the virtual functions
|
||||||
|
@GstRTPBaseDepayload.process or
|
||||||
|
@GstRTPBaseDepayload.process_rtp_packet must tell the base class
|
||||||
|
what happens to the current RTP packet. By default the base class
|
||||||
|
assumes that the packet payload is used with the next output
|
||||||
|
buffer.
|
||||||
|
|
||||||
|
If the RTP packet will not be used with an output buffer
|
||||||
|
gst_rtp_base_depayload_dropped() must be called. A typical
|
||||||
|
situation would be if we are waiting for a keyframe.
|
||||||
|
|
||||||
|
If the RTP packet will be used but not with the current output
|
||||||
|
buffer but with the next one gst_rtp_base_depayload_delayed() must
|
||||||
|
be called. This may happen if the current RTP packet signals the
|
||||||
|
start of a new output buffer and the currently processed output
|
||||||
|
buffer will be pushed first. The undelay happens implicitly once
|
||||||
|
the current buffer has been pushed or
|
||||||
|
gst_rtp_base_depayload_flush() has been called.
|
||||||
|
|
||||||
|
If gst_rtp_base_depayload_flush() is called all RTP packets that
|
||||||
|
have not been dropped since the last output buffer are dropped,
|
||||||
|
e.g. if an output buffer is discarded due to malformed data. This
|
||||||
|
may or may not include the current RTP packet depending on the 2nd
|
||||||
|
parameter @keep_current.
|
||||||
|
|
||||||
|
Be aware that in case gst_rtp_base_depayload_push_list() is used
|
||||||
|
each buffer will see the same list of RTP header extensions.</doc>
|
||||||
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
||||||
<virtual-method name="handle_event">
|
<virtual-method name="handle_event">
|
||||||
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
||||||
|
@ -2404,6 +2436,100 @@ audio codec</doc>
|
||||||
</parameter>
|
</parameter>
|
||||||
</parameters>
|
</parameters>
|
||||||
</virtual-method>
|
</virtual-method>
|
||||||
|
<method name="delayed" c:identifier="gst_rtp_base_depayload_delayed" version="1.24">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Called from @GstRTPBaseDepayload.process or
|
||||||
|
@GstRTPBaseDepayload.process_rtp_packet when the depayloader needs
|
||||||
|
to keep the current input RTP header for use with the next output
|
||||||
|
buffer.
|
||||||
|
|
||||||
|
The delayed buffer will remain until the end of processing the
|
||||||
|
current output buffer and then enqueued for processing with the
|
||||||
|
next output buffer.
|
||||||
|
|
||||||
|
A typical use-case is when the depayloader implementation will
|
||||||
|
start a new output buffer for the current input RTP buffer but push
|
||||||
|
the current output buffer first.
|
||||||
|
|
||||||
|
Must be called with the stream lock held.</doc>
|
||||||
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
||||||
|
<return-value transfer-ownership="none">
|
||||||
|
<type name="none" c:type="void"/>
|
||||||
|
</return-value>
|
||||||
|
<parameters>
|
||||||
|
<instance-parameter name="depayload" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">a #GstRTPBaseDepayload</doc>
|
||||||
|
<type name="RTPBaseDepayload" c:type="GstRTPBaseDepayload*"/>
|
||||||
|
</instance-parameter>
|
||||||
|
</parameters>
|
||||||
|
</method>
|
||||||
|
<method name="dropped" c:identifier="gst_rtp_base_depayload_dropped" version="1.24">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Called from @GstRTPBaseDepayload.process or
|
||||||
|
@GstRTPBaseDepayload.process_rtp_packet if the depayloader does not
|
||||||
|
use the current buffer for the output buffer. This will either drop
|
||||||
|
the delayed buffer or the last buffer from the header extension
|
||||||
|
cache.
|
||||||
|
|
||||||
|
A typical use-case is when the depayloader implementation is
|
||||||
|
dropping an input RTP buffer while waiting for the first keyframe.
|
||||||
|
|
||||||
|
Must be called with the stream lock held.</doc>
|
||||||
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
||||||
|
<return-value transfer-ownership="none">
|
||||||
|
<type name="none" c:type="void"/>
|
||||||
|
</return-value>
|
||||||
|
<parameters>
|
||||||
|
<instance-parameter name="depayload" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">a #GstRTPBaseDepayload</doc>
|
||||||
|
<type name="RTPBaseDepayload" c:type="GstRTPBaseDepayload*"/>
|
||||||
|
</instance-parameter>
|
||||||
|
</parameters>
|
||||||
|
</method>
|
||||||
|
<method name="flush" c:identifier="gst_rtp_base_depayload_flush" version="1.24">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">If @GstRTPBaseDepayload.process or
|
||||||
|
@GstRTPBaseDepayload.process_rtp_packet drop an output buffer this
|
||||||
|
function tells the base class to flush header extension cache as
|
||||||
|
well.
|
||||||
|
|
||||||
|
This will not drop an input RTP header marked as delayed from
|
||||||
|
gst_rtp_base_depayload_delayed().
|
||||||
|
|
||||||
|
If @keep_current is %TRUE the current input RTP header will be kept
|
||||||
|
and enqueued after flushing the previous input RTP headers.
|
||||||
|
|
||||||
|
A typical use-case for @keep_current is when the depayloader
|
||||||
|
implementation invalidates the current output buffer and starts a
|
||||||
|
new one with the current RTP input buffer.
|
||||||
|
|
||||||
|
Must be called with the stream lock held.</doc>
|
||||||
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
||||||
|
<return-value transfer-ownership="none">
|
||||||
|
<type name="none" c:type="void"/>
|
||||||
|
</return-value>
|
||||||
|
<parameters>
|
||||||
|
<instance-parameter name="depayload" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">a #GstRTPBaseDepayload</doc>
|
||||||
|
<type name="RTPBaseDepayload" c:type="GstRTPBaseDepayload*"/>
|
||||||
|
</instance-parameter>
|
||||||
|
<parameter name="keep_current" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">if the current RTP buffer shall be kept</doc>
|
||||||
|
<type name="gboolean" c:type="gboolean"/>
|
||||||
|
</parameter>
|
||||||
|
</parameters>
|
||||||
|
</method>
|
||||||
|
<method name="is_aggregate_hdrext_enabled" c:identifier="gst_rtp_base_depayload_is_aggregate_hdrext_enabled" version="1.24">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Queries whether header extensions will be aggregated per depayloaded buffers.</doc>
|
||||||
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
||||||
|
<return-value transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">%TRUE if aggregate-header-extension is enabled.</doc>
|
||||||
|
<type name="gboolean" c:type="gboolean"/>
|
||||||
|
</return-value>
|
||||||
|
<parameters>
|
||||||
|
<instance-parameter name="depayload" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">a #GstRTPBaseDepayload</doc>
|
||||||
|
<type name="RTPBaseDepayload" c:type="GstRTPBaseDepayload*"/>
|
||||||
|
</instance-parameter>
|
||||||
|
</parameters>
|
||||||
|
</method>
|
||||||
<method name="is_source_info_enabled" c:identifier="gst_rtp_base_depayload_is_source_info_enabled" version="1.16">
|
<method name="is_source_info_enabled" c:identifier="gst_rtp_base_depayload_is_source_info_enabled" version="1.16">
|
||||||
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Queries whether #GstRTPSourceMeta will be added to depayloaded buffers.</doc>
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Queries whether #GstRTPSourceMeta will be added to depayloaded buffers.</doc>
|
||||||
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
||||||
|
@ -2459,6 +2585,23 @@ the outgoing buffer when it didn't have a timestamp already.</doc>
|
||||||
</parameter>
|
</parameter>
|
||||||
</parameters>
|
</parameters>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="set_aggregate_hdrext_enabled" c:identifier="gst_rtp_base_depayload_set_aggregate_hdrext_enabled" version="1.24">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Enable or disable aggregating header extensions.</doc>
|
||||||
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
||||||
|
<return-value transfer-ownership="none">
|
||||||
|
<type name="none" c:type="void"/>
|
||||||
|
</return-value>
|
||||||
|
<parameters>
|
||||||
|
<instance-parameter name="depayload" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">a #GstRTPBaseDepayload</doc>
|
||||||
|
<type name="RTPBaseDepayload" c:type="GstRTPBaseDepayload*"/>
|
||||||
|
</instance-parameter>
|
||||||
|
<parameter name="enable" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">whether to aggregate header extensions per output buffer</doc>
|
||||||
|
<type name="gboolean" c:type="gboolean"/>
|
||||||
|
</parameter>
|
||||||
|
</parameters>
|
||||||
|
</method>
|
||||||
<method name="set_source_info_enabled" c:identifier="gst_rtp_base_depayload_set_source_info_enabled" version="1.16">
|
<method name="set_source_info_enabled" c:identifier="gst_rtp_base_depayload_set_source_info_enabled" version="1.16">
|
||||||
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Enable or disable adding #GstRTPSourceMeta to depayloaded buffers.</doc>
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.c">Enable or disable adding #GstRTPSourceMeta to depayloaded buffers.</doc>
|
||||||
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasedepayload.h"/>
|
||||||
|
|
|
@ -24,6 +24,38 @@
|
||||||
* @short_description: Base class for RTP depayloader
|
* @short_description: Base class for RTP depayloader
|
||||||
*
|
*
|
||||||
* Provides a base class for RTP depayloaders
|
* Provides a base class for RTP depayloaders
|
||||||
|
*
|
||||||
|
* In order to handle RTP header extensions correctly if the
|
||||||
|
* depayloader aggregates multiple RTP packet payloads into one output
|
||||||
|
* buffer this class provides the function
|
||||||
|
* gst_rtp_base_depayload_set_aggregate_hdrext_enabled(). If the
|
||||||
|
* aggregation is enabled the virtual functions
|
||||||
|
* @GstRTPBaseDepayload.process or
|
||||||
|
* @GstRTPBaseDepayload.process_rtp_packet must tell the base class
|
||||||
|
* what happens to the current RTP packet. By default the base class
|
||||||
|
* assumes that the packet payload is used with the next output
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* If the RTP packet will not be used with an output buffer
|
||||||
|
* gst_rtp_base_depayload_dropped() must be called. A typical
|
||||||
|
* situation would be if we are waiting for a keyframe.
|
||||||
|
*
|
||||||
|
* If the RTP packet will be used but not with the current output
|
||||||
|
* buffer but with the next one gst_rtp_base_depayload_delayed() must
|
||||||
|
* be called. This may happen if the current RTP packet signals the
|
||||||
|
* start of a new output buffer and the currently processed output
|
||||||
|
* buffer will be pushed first. The undelay happens implicitly once
|
||||||
|
* the current buffer has been pushed or
|
||||||
|
* gst_rtp_base_depayload_flush() has been called.
|
||||||
|
*
|
||||||
|
* If gst_rtp_base_depayload_flush() is called all RTP packets that
|
||||||
|
* have not been dropped since the last output buffer are dropped,
|
||||||
|
* e.g. if an output buffer is discarded due to malformed data. This
|
||||||
|
* may or may not include the current RTP packet depending on the 2nd
|
||||||
|
* parameter @keep_current.
|
||||||
|
*
|
||||||
|
* Be aware that in case gst_rtp_base_depayload_push_list() is used
|
||||||
|
* each buffer will see the same list of RTP header extensions.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -75,6 +107,13 @@ struct _GstRTPBaseDepayloadPrivate
|
||||||
|
|
||||||
/* array of GstRTPHeaderExtension's * */
|
/* array of GstRTPHeaderExtension's * */
|
||||||
GPtrArray *header_exts;
|
GPtrArray *header_exts;
|
||||||
|
|
||||||
|
/* maintain buffer list for header extensions read() */
|
||||||
|
gboolean hdrext_aggregate;
|
||||||
|
GstBufferList *hdrext_buffers;
|
||||||
|
GstBuffer *hdrext_delayed;
|
||||||
|
GstBuffer *hdrext_outbuf;
|
||||||
|
gboolean hdrext_read_result;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Filter signals and args */
|
/* Filter signals and args */
|
||||||
|
@ -139,6 +178,11 @@ static void gst_rtp_base_depayload_add_extension (GstRTPBaseDepayload *
|
||||||
static void gst_rtp_base_depayload_clear_extensions (GstRTPBaseDepayload *
|
static void gst_rtp_base_depayload_clear_extensions (GstRTPBaseDepayload *
|
||||||
rtpbasepayload);
|
rtpbasepayload);
|
||||||
|
|
||||||
|
static gboolean gst_rtp_base_depayload_operate_hdrext_buffer (GstBuffer **
|
||||||
|
buffer, guint idx, gpointer depayloader);
|
||||||
|
static void gst_rtp_base_depayload_reset_hdrext_buffers (GstRTPBaseDepayload *
|
||||||
|
rtpbasepayload);
|
||||||
|
|
||||||
GType
|
GType
|
||||||
gst_rtp_base_depayload_get_type (void)
|
gst_rtp_base_depayload_get_type (void)
|
||||||
{
|
{
|
||||||
|
@ -404,11 +448,13 @@ gst_rtp_base_depayload_init (GstRTPBaseDepayload * filter,
|
||||||
priv->source_info = DEFAULT_SOURCE_INFO;
|
priv->source_info = DEFAULT_SOURCE_INFO;
|
||||||
priv->max_reorder = DEFAULT_MAX_REORDER;
|
priv->max_reorder = DEFAULT_MAX_REORDER;
|
||||||
priv->auto_hdr_ext = DEFAULT_AUTO_HEADER_EXTENSION;
|
priv->auto_hdr_ext = DEFAULT_AUTO_HEADER_EXTENSION;
|
||||||
|
priv->hdrext_aggregate = FALSE;
|
||||||
|
|
||||||
gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
|
gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
|
||||||
|
|
||||||
priv->header_exts =
|
priv->header_exts =
|
||||||
g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
|
g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
|
||||||
|
priv->hdrext_buffers = gst_buffer_list_new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -417,7 +463,7 @@ gst_rtp_base_depayload_finalize (GObject * object)
|
||||||
GstRTPBaseDepayload *rtpbasedepayload = GST_RTP_BASE_DEPAYLOAD (object);
|
GstRTPBaseDepayload *rtpbasedepayload = GST_RTP_BASE_DEPAYLOAD (object);
|
||||||
|
|
||||||
g_ptr_array_unref (rtpbasedepayload->priv->header_exts);
|
g_ptr_array_unref (rtpbasedepayload->priv->header_exts);
|
||||||
rtpbasedepayload->priv->header_exts = NULL;
|
gst_clear_buffer_list (&rtpbasedepayload->priv->hdrext_buffers);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -808,6 +854,22 @@ gst_rtp_base_depayload_handle_buffer (GstRTPBaseDepayload * filter,
|
||||||
|
|
||||||
priv->input_buffer = in;
|
priv->input_buffer = in;
|
||||||
|
|
||||||
|
if (discont) {
|
||||||
|
gst_rtp_base_depayload_reset_hdrext_buffers (filter);
|
||||||
|
g_assert_null (priv->hdrext_delayed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update RTP buffer cache for header extensions */
|
||||||
|
if (priv->hdrext_aggregate) {
|
||||||
|
GstBuffer *b = gst_buffer_new ();
|
||||||
|
/* make a copy of the buffer that only contains the RTP header
|
||||||
|
with the extensions to not waste too much memory */
|
||||||
|
guint s = gst_rtp_buffer_get_header_len (&rtp);
|
||||||
|
gst_buffer_copy_into (b, in,
|
||||||
|
GST_BUFFER_COPY_MEMORY | GST_BUFFER_COPY_DEEP, 0, s);
|
||||||
|
gst_buffer_list_add (priv->hdrext_buffers, b);
|
||||||
|
}
|
||||||
|
|
||||||
if (process_rtp_packet_func != NULL) {
|
if (process_rtp_packet_func != NULL) {
|
||||||
out_buf = process_rtp_packet_func (filter, &rtp);
|
out_buf = process_rtp_packet_func (filter, &rtp);
|
||||||
gst_rtp_buffer_unmap (&rtp);
|
gst_rtp_buffer_unmap (&rtp);
|
||||||
|
@ -820,10 +882,22 @@ gst_rtp_base_depayload_handle_buffer (GstRTPBaseDepayload * filter,
|
||||||
|
|
||||||
/* let's send it out to processing */
|
/* let's send it out to processing */
|
||||||
if (out_buf) {
|
if (out_buf) {
|
||||||
if (priv->process_flow_ret == GST_FLOW_OK)
|
if (priv->process_flow_ret == GST_FLOW_OK) {
|
||||||
priv->process_flow_ret = gst_rtp_base_depayload_push (filter, out_buf);
|
priv->process_flow_ret = gst_rtp_base_depayload_push (filter, out_buf);
|
||||||
else
|
} else {
|
||||||
gst_buffer_unref (out_buf);
|
gst_buffer_unref (out_buf);
|
||||||
|
gst_rtp_base_depayload_reset_hdrext_buffers (filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the current buffer is delayed the depayloader should either
|
||||||
|
have called gst_rtp_base_depayload_push() internally or returned
|
||||||
|
a buffer that's pushed, either way the buffer cache should be
|
||||||
|
empty here and we append the delayed buffer */
|
||||||
|
if (priv->hdrext_delayed) {
|
||||||
|
g_assert_true (gst_buffer_list_length (priv->hdrext_buffers) == 0);
|
||||||
|
gst_buffer_list_add (priv->hdrext_buffers, priv->hdrext_delayed);
|
||||||
|
priv->hdrext_delayed = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_buffer_unref (in);
|
gst_buffer_unref (in);
|
||||||
|
@ -1283,12 +1357,34 @@ out:
|
||||||
return needs_src_caps_update;
|
return needs_src_caps_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtp_base_depayload_operate_hdrext_buffer (GstBuffer ** buffer,
|
||||||
|
guint idx, gpointer depayloader)
|
||||||
|
{
|
||||||
|
GstRTPBaseDepayload *depayload = depayloader;
|
||||||
|
|
||||||
|
depayload->priv->hdrext_read_result |=
|
||||||
|
read_rtp_header_extensions (depayload, *buffer,
|
||||||
|
depayload->priv->hdrext_outbuf);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtp_base_depayload_reset_hdrext_buffers (GstRTPBaseDepayload * depayload)
|
||||||
|
{
|
||||||
|
GstRTPBaseDepayloadPrivate *priv = depayload->priv;
|
||||||
|
|
||||||
|
gst_buffer_list_unref (priv->hdrext_buffers);
|
||||||
|
priv->hdrext_buffers = gst_buffer_list_new ();
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_rtp_base_depayload_set_headers (GstRTPBaseDepayload * depayload,
|
gst_rtp_base_depayload_set_headers (GstRTPBaseDepayload * depayload,
|
||||||
GstBuffer * buffer)
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstRTPBaseDepayloadPrivate *priv = depayload->priv;
|
GstRTPBaseDepayloadPrivate *priv = depayload->priv;
|
||||||
GstClockTime pts, dts, duration;
|
GstClockTime pts, dts, duration;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
pts = GST_BUFFER_PTS (buffer);
|
pts = GST_BUFFER_PTS (buffer);
|
||||||
dts = GST_BUFFER_DTS (buffer);
|
dts = GST_BUFFER_DTS (buffer);
|
||||||
|
@ -1318,10 +1414,25 @@ gst_rtp_base_depayload_set_headers (GstRTPBaseDepayload * depayload,
|
||||||
if (priv->source_info)
|
if (priv->source_info)
|
||||||
add_rtp_source_meta (buffer, priv->input_buffer);
|
add_rtp_source_meta (buffer, priv->input_buffer);
|
||||||
|
|
||||||
return read_rtp_header_extensions (depayload, priv->input_buffer, buffer);
|
if (priv->hdrext_aggregate) {
|
||||||
|
priv->hdrext_read_result = FALSE;
|
||||||
|
priv->hdrext_outbuf = buffer;
|
||||||
|
/* if we have an empty list but a delayed RTP buffer let's use it */
|
||||||
|
if (!gst_buffer_list_length (priv->hdrext_buffers) &&
|
||||||
|
priv->hdrext_delayed) {
|
||||||
|
gst_buffer_list_add (priv->hdrext_buffers, priv->hdrext_delayed);
|
||||||
|
priv->hdrext_delayed = NULL;
|
||||||
|
}
|
||||||
|
gst_buffer_list_foreach (priv->hdrext_buffers,
|
||||||
|
gst_rtp_base_depayload_operate_hdrext_buffer, depayload);
|
||||||
|
ret = priv->hdrext_read_result;
|
||||||
|
priv->hdrext_outbuf = NULL;
|
||||||
|
} else {
|
||||||
|
ret = read_rtp_header_extensions (depayload, priv->input_buffer, buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -1447,6 +1558,8 @@ gst_rtp_base_depayload_do_push (GstRTPBaseDepayload * filter, gboolean is_list,
|
||||||
gst_clear_buffer (&buf);
|
gst_clear_buffer (&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_rtp_base_depayload_reset_hdrext_buffers (filter);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1718,3 +1831,146 @@ gst_rtp_base_depayload_is_source_info_enabled (GstRTPBaseDepayload * depayload)
|
||||||
{
|
{
|
||||||
return depayload->priv->source_info;
|
return depayload->priv->source_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtp_base_depayload_set_aggregate_hdrext_enabled:
|
||||||
|
* @depayload: a #GstRTPBaseDepayload
|
||||||
|
* @enable: whether to aggregate header extensions per output buffer
|
||||||
|
*
|
||||||
|
* Enable or disable aggregating header extensions.
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
gst_rtp_base_depayload_set_aggregate_hdrext_enabled (GstRTPBaseDepayload *
|
||||||
|
depayload, gboolean enable)
|
||||||
|
{
|
||||||
|
depayload->priv->hdrext_aggregate = enable;
|
||||||
|
if (!enable)
|
||||||
|
gst_rtp_base_depayload_reset_hdrext_buffers (depayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtp_base_depayload_is_aggregate_hdrext_enabled:
|
||||||
|
* @depayload: a #GstRTPBaseDepayload
|
||||||
|
*
|
||||||
|
* Queries whether header extensions will be aggregated per depayloaded buffers.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if aggregate-header-extension is enabled.
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
gst_rtp_base_depayload_is_aggregate_hdrext_enabled (GstRTPBaseDepayload *
|
||||||
|
depayload)
|
||||||
|
{
|
||||||
|
return depayload->priv->hdrext_aggregate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtp_base_depayload_dropped:
|
||||||
|
* @depayload: a #GstRTPBaseDepayload
|
||||||
|
*
|
||||||
|
* Called from @GstRTPBaseDepayload.process or
|
||||||
|
* @GstRTPBaseDepayload.process_rtp_packet if the depayloader does not
|
||||||
|
* use the current buffer for the output buffer. This will either drop
|
||||||
|
* the delayed buffer or the last buffer from the header extension
|
||||||
|
* cache.
|
||||||
|
*
|
||||||
|
* A typical use-case is when the depayloader implementation is
|
||||||
|
* dropping an input RTP buffer while waiting for the first keyframe.
|
||||||
|
*
|
||||||
|
* Must be called with the stream lock held.
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
gst_rtp_base_depayload_dropped (GstRTPBaseDepayload * depayload)
|
||||||
|
{
|
||||||
|
GstRTPBaseDepayloadPrivate *priv = depayload->priv;
|
||||||
|
guint l = gst_buffer_list_length (priv->hdrext_buffers);
|
||||||
|
|
||||||
|
if (priv->hdrext_delayed) {
|
||||||
|
gst_clear_buffer (&priv->hdrext_delayed);
|
||||||
|
} else if (l) {
|
||||||
|
gst_buffer_list_remove (priv->hdrext_buffers, l - 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtp_base_depayload_delayed:
|
||||||
|
* @depayload: a #GstRTPBaseDepayload
|
||||||
|
*
|
||||||
|
* Called from @GstRTPBaseDepayload.process or
|
||||||
|
* @GstRTPBaseDepayload.process_rtp_packet when the depayloader needs
|
||||||
|
* to keep the current input RTP header for use with the next output
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* The delayed buffer will remain until the end of processing the
|
||||||
|
* current output buffer and then enqueued for processing with the
|
||||||
|
* next output buffer.
|
||||||
|
*
|
||||||
|
* A typical use-case is when the depayloader implementation will
|
||||||
|
* start a new output buffer for the current input RTP buffer but push
|
||||||
|
* the current output buffer first.
|
||||||
|
*
|
||||||
|
* Must be called with the stream lock held.
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
gst_rtp_base_depayload_delayed (GstRTPBaseDepayload * depayload)
|
||||||
|
{
|
||||||
|
GstRTPBaseDepayloadPrivate *priv = depayload->priv;
|
||||||
|
guint l = gst_buffer_list_length (priv->hdrext_buffers);
|
||||||
|
|
||||||
|
if (l) {
|
||||||
|
priv->hdrext_delayed = gst_buffer_list_get (priv->hdrext_buffers, l - 1);
|
||||||
|
gst_buffer_ref (priv->hdrext_delayed);
|
||||||
|
gst_buffer_list_remove (priv->hdrext_buffers, l - 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtp_base_depayload_flush:
|
||||||
|
* @depayload: a #GstRTPBaseDepayload
|
||||||
|
* @keep_current: if the current RTP buffer shall be kept
|
||||||
|
*
|
||||||
|
* If @GstRTPBaseDepayload.process or
|
||||||
|
* @GstRTPBaseDepayload.process_rtp_packet drop an output buffer this
|
||||||
|
* function tells the base class to flush header extension cache as
|
||||||
|
* well.
|
||||||
|
*
|
||||||
|
* This will not drop an input RTP header marked as delayed from
|
||||||
|
* gst_rtp_base_depayload_delayed().
|
||||||
|
*
|
||||||
|
* If @keep_current is %TRUE the current input RTP header will be kept
|
||||||
|
* and enqueued after flushing the previous input RTP headers.
|
||||||
|
*
|
||||||
|
* A typical use-case for @keep_current is when the depayloader
|
||||||
|
* implementation invalidates the current output buffer and starts a
|
||||||
|
* new one with the current RTP input buffer.
|
||||||
|
*
|
||||||
|
* Must be called with the stream lock held.
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
gst_rtp_base_depayload_flush (GstRTPBaseDepayload * depayload,
|
||||||
|
gboolean keep_current)
|
||||||
|
{
|
||||||
|
GstRTPBaseDepayloadPrivate *priv = depayload->priv;
|
||||||
|
guint l = gst_buffer_list_length (priv->hdrext_buffers);
|
||||||
|
|
||||||
|
/* if the current buffer shall not be kept or has already been
|
||||||
|
removed from the cache clear the cache */
|
||||||
|
if (!keep_current || priv->hdrext_delayed) {
|
||||||
|
gst_rtp_base_depayload_reset_hdrext_buffers (depayload);
|
||||||
|
} else if (l) {
|
||||||
|
/* clear all cached buffers (if any) except the delayed */
|
||||||
|
GstBuffer *b = gst_buffer_list_get (priv->hdrext_buffers, l - 1);
|
||||||
|
gst_buffer_ref (b);
|
||||||
|
gst_rtp_base_depayload_reset_hdrext_buffers (depayload);
|
||||||
|
gst_buffer_list_add (priv->hdrext_buffers, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -127,6 +127,22 @@ GST_RTP_API
|
||||||
void gst_rtp_base_depayload_set_source_info_enabled (GstRTPBaseDepayload * depayload,
|
void gst_rtp_base_depayload_set_source_info_enabled (GstRTPBaseDepayload * depayload,
|
||||||
gboolean enable);
|
gboolean enable);
|
||||||
|
|
||||||
|
GST_RTP_API
|
||||||
|
void gst_rtp_base_depayload_dropped (GstRTPBaseDepayload * depayload);
|
||||||
|
|
||||||
|
GST_RTP_API
|
||||||
|
void gst_rtp_base_depayload_delayed (GstRTPBaseDepayload * depayload);
|
||||||
|
|
||||||
|
GST_RTP_API
|
||||||
|
void gst_rtp_base_depayload_flush (GstRTPBaseDepayload * depayload,
|
||||||
|
gboolean keep_current);
|
||||||
|
|
||||||
|
GST_RTP_API
|
||||||
|
gboolean gst_rtp_base_depayload_is_aggregate_hdrext_enabled (GstRTPBaseDepayload * depayload);
|
||||||
|
|
||||||
|
GST_RTP_API
|
||||||
|
void gst_rtp_base_depayload_set_aggregate_hdrext_enabled (GstRTPBaseDepayload * depayload,
|
||||||
|
gboolean enable);
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTPBaseDepayload, gst_object_unref)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTPBaseDepayload, gst_object_unref)
|
||||||
|
|
||||||
|
|
|
@ -48,8 +48,17 @@ typedef enum
|
||||||
GST_RTP_DUMMY_RETURN_TO_PUSH,
|
GST_RTP_DUMMY_RETURN_TO_PUSH,
|
||||||
GST_RTP_DUMMY_USE_PUSH_FUNC,
|
GST_RTP_DUMMY_USE_PUSH_FUNC,
|
||||||
GST_RTP_DUMMY_USE_PUSH_LIST_FUNC,
|
GST_RTP_DUMMY_USE_PUSH_LIST_FUNC,
|
||||||
|
GST_RTP_DUMMY_USE_PUSH_AGGREGATE_FUNC,
|
||||||
} GstRtpDummyPushMethod;
|
} GstRtpDummyPushMethod;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
GST_RTP_DUMMY_PUSH_AGGREGATE_DEFAULT,
|
||||||
|
GST_RTP_DUMMY_PUSH_AGGREGATE_DROP,
|
||||||
|
GST_RTP_DUMMY_PUSH_AGGREGATE_DELAYED,
|
||||||
|
GST_RTP_DUMMY_PUSH_AGGREGATE_FLUSH,
|
||||||
|
} GstRtpDummyPushAggregateMethod;
|
||||||
|
|
||||||
typedef struct _GstRtpDummyDepay GstRtpDummyDepay;
|
typedef struct _GstRtpDummyDepay GstRtpDummyDepay;
|
||||||
typedef struct _GstRtpDummyDepayClass GstRtpDummyDepayClass;
|
typedef struct _GstRtpDummyDepayClass GstRtpDummyDepayClass;
|
||||||
|
|
||||||
|
@ -60,6 +69,10 @@ struct _GstRtpDummyDepay
|
||||||
|
|
||||||
GstRtpDummyPushMethod push_method;
|
GstRtpDummyPushMethod push_method;
|
||||||
guint num_buffers_in_blist;
|
guint num_buffers_in_blist;
|
||||||
|
|
||||||
|
GstRtpDummyPushAggregateMethod aggregate_method;
|
||||||
|
guint num_buffers_to_aggregate;
|
||||||
|
guint num_buffers_aggregated;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRtpDummyDepayClass
|
struct _GstRtpDummyDepayClass
|
||||||
|
@ -112,6 +125,8 @@ gst_rtp_dummy_depay_init (GstRtpDummyDepay * depay)
|
||||||
{
|
{
|
||||||
depay->rtptime = 0;
|
depay->rtptime = 0;
|
||||||
depay->num_buffers_in_blist = 1;
|
depay->num_buffers_in_blist = 1;
|
||||||
|
depay->num_buffers_to_aggregate = 1;
|
||||||
|
depay->num_buffers_aggregated = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstRtpDummyDepay *
|
static GstRtpDummyDepay *
|
||||||
|
@ -180,6 +195,34 @@ gst_rtp_dummy_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
|
||||||
gst_rtp_base_depayload_push_list (depayload, blist);
|
gst_rtp_base_depayload_push_list (depayload, blist);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GST_RTP_DUMMY_USE_PUSH_AGGREGATE_FUNC:
|
||||||
|
++self->num_buffers_aggregated;
|
||||||
|
if (self->num_buffers_aggregated != self->num_buffers_to_aggregate) {
|
||||||
|
switch (self->aggregate_method) {
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_DROP:
|
||||||
|
gst_rtp_base_depayload_dropped (depayload);
|
||||||
|
break;
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_DEFAULT:
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_DELAYED:
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_FLUSH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gst_clear_buffer (&outbuf);
|
||||||
|
} else {
|
||||||
|
switch (self->aggregate_method) {
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_DELAYED:
|
||||||
|
gst_rtp_base_depayload_delayed (depayload);
|
||||||
|
break;
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_FLUSH:
|
||||||
|
gst_rtp_base_depayload_flush (depayload, TRUE);
|
||||||
|
break;
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_DROP:
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_DEFAULT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self->num_buffers_aggregated = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case GST_RTP_DUMMY_RETURN_TO_PUSH:
|
case GST_RTP_DUMMY_RETURN_TO_PUSH:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1877,6 +1920,170 @@ GST_START_TEST (rtp_base_depayload_hdr_ext_caps_change)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
hdr_ext_aggregate_chain_func (GstPad * pad, GstObject * parent,
|
||||||
|
GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstFlowReturn res;
|
||||||
|
GstCaps *caps;
|
||||||
|
guint val;
|
||||||
|
GstPad *srcpad;
|
||||||
|
GstElement *depay;
|
||||||
|
static gboolean first = TRUE;
|
||||||
|
static guint expected_caps_val = 0;
|
||||||
|
|
||||||
|
res = gst_check_chain_func (pad, parent, buffer);
|
||||||
|
if (res != GST_FLOW_OK) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
caps = gst_pad_get_current_caps (pad);
|
||||||
|
|
||||||
|
fail_unless (gst_structure_get_uint (gst_caps_get_structure (caps, 0),
|
||||||
|
"dummy-hdrext-val", &val));
|
||||||
|
|
||||||
|
srcpad = gst_pad_get_peer (pad);
|
||||||
|
depay = gst_pad_get_parent_element (srcpad);
|
||||||
|
|
||||||
|
switch (GST_RTP_DUMMY_DEPAY (depay)->aggregate_method) {
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_DEFAULT:
|
||||||
|
/* Every fifth buffer increments "dummy-hdrext-val", but we
|
||||||
|
aggregate 5 buffers per output buffer so we increment for every
|
||||||
|
output buffer. */
|
||||||
|
expected_caps_val++;
|
||||||
|
break;
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_DROP:
|
||||||
|
/* We aggregate 5 buffers per output buffer but drop 4 of them
|
||||||
|
from the buffer cache. */
|
||||||
|
if (g_list_length (buffers) % 5 == 1) {
|
||||||
|
expected_caps_val++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_DELAYED:
|
||||||
|
/* We aggregate 6 buffers per output buffer but delay the 6th one
|
||||||
|
which will then account to the 2nd output buffer. Thus the 1st
|
||||||
|
output buffer will process 5 header extensions (val increments
|
||||||
|
by one) whereas the 2nd buffer will process 6 (val increments
|
||||||
|
by two)! */
|
||||||
|
if (first) {
|
||||||
|
first = FALSE;
|
||||||
|
expected_caps_val++;
|
||||||
|
} else {
|
||||||
|
expected_caps_val += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_RTP_DUMMY_PUSH_AGGREGATE_FLUSH:
|
||||||
|
/* We aggregate 5 buffers per output buffer but flush 4 of them
|
||||||
|
from the hdr ext buffer cache. */
|
||||||
|
if (g_list_length (buffers) % 5 == 1) {
|
||||||
|
expected_caps_val++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_object_unref (depay);
|
||||||
|
gst_object_unref (srcpad);
|
||||||
|
|
||||||
|
fail_unless_equals_int (expected_caps_val, val);
|
||||||
|
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hdr_ext_aggregate_test (gint n_buffers, gint n_aggregate,
|
||||||
|
GstRtpDummyPushAggregateMethod method)
|
||||||
|
{
|
||||||
|
GstRTPHeaderExtension *ext;
|
||||||
|
State *state;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
state = create_depayloader ("application/x-rtp", NULL);
|
||||||
|
gst_rtp_base_depayload_set_aggregate_hdrext_enabled (GST_RTP_BASE_DEPAYLOAD
|
||||||
|
(state->element), TRUE);
|
||||||
|
gst_pad_set_chain_function (state->sinkpad, hdr_ext_aggregate_chain_func);
|
||||||
|
ext = rtp_dummy_hdr_ext_new ();
|
||||||
|
gst_rtp_header_extension_set_id (ext, 1);
|
||||||
|
|
||||||
|
GST_RTP_DUMMY_DEPAY (state->element)->push_method =
|
||||||
|
GST_RTP_DUMMY_USE_PUSH_AGGREGATE_FUNC;
|
||||||
|
GST_RTP_DUMMY_DEPAY (state->element)->num_buffers_to_aggregate = n_aggregate;
|
||||||
|
GST_RTP_DUMMY_DEPAY (state->element)->aggregate_method = method;
|
||||||
|
|
||||||
|
g_signal_emit_by_name (state->element, "add-extension", ext);
|
||||||
|
set_state (state, GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
for (i = 0; i < n_buffers; ++i) {
|
||||||
|
push_rtp_buffer (state, "pts", 0 * GST_SECOND,
|
||||||
|
"rtptime", G_GUINT64_CONSTANT (0x1234), "seq", 0x4242 + i, "hdrext-1",
|
||||||
|
ext, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_state (state, GST_STATE_NULL);
|
||||||
|
validate_buffers_received (n_buffers / n_aggregate);
|
||||||
|
gst_object_unref (ext);
|
||||||
|
destroy_depayloader (state);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_START_TEST (rtp_base_depayload_hdr_ext_aggregate)
|
||||||
|
{
|
||||||
|
const gint num_buffers = 30;
|
||||||
|
const gint num_buffers_aggregate = 5; /* must match the modulo from
|
||||||
|
hdrext */
|
||||||
|
|
||||||
|
fail_unless_equals_int (num_buffers % num_buffers_aggregate, 0);
|
||||||
|
|
||||||
|
hdr_ext_aggregate_test (num_buffers, num_buffers_aggregate,
|
||||||
|
GST_RTP_DUMMY_PUSH_AGGREGATE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (rtp_base_depayload_hdr_ext_aggregate_drop)
|
||||||
|
{
|
||||||
|
const gint num_buffers = 30;
|
||||||
|
const gint num_buffers_aggregate = 5; /* must match the modulo from
|
||||||
|
hdrext */
|
||||||
|
|
||||||
|
fail_unless_equals_int (num_buffers % num_buffers_aggregate, 0);
|
||||||
|
|
||||||
|
hdr_ext_aggregate_test (num_buffers, num_buffers_aggregate,
|
||||||
|
GST_RTP_DUMMY_PUSH_AGGREGATE_DROP);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (rtp_base_depayload_hdr_ext_aggregate_delayed)
|
||||||
|
{
|
||||||
|
const gint num_buffers = 12; /* must be two times
|
||||||
|
num_buffers_aggregate */
|
||||||
|
const gint num_buffers_aggregate = 6; /* must match the modulo from
|
||||||
|
hdrext + 1 */
|
||||||
|
|
||||||
|
fail_unless_equals_int (num_buffers % num_buffers_aggregate, 0);
|
||||||
|
fail_unless_equals_int (num_buffers / num_buffers_aggregate, 2);
|
||||||
|
|
||||||
|
hdr_ext_aggregate_test (num_buffers, num_buffers_aggregate,
|
||||||
|
GST_RTP_DUMMY_PUSH_AGGREGATE_DELAYED);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (rtp_base_depayload_hdr_ext_aggregate_flush)
|
||||||
|
{
|
||||||
|
const gint num_buffers = 30;
|
||||||
|
const gint num_buffers_aggregate = 5; /* must match the modulo from
|
||||||
|
hdrext */
|
||||||
|
|
||||||
|
fail_unless_equals_int (num_buffers % num_buffers_aggregate, 0);
|
||||||
|
|
||||||
|
hdr_ext_aggregate_test (num_buffers, num_buffers_aggregate,
|
||||||
|
GST_RTP_DUMMY_PUSH_AGGREGATE_FLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
rtp_basepayloading_suite (void)
|
rtp_basepayloading_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -1921,7 +2128,10 @@ rtp_basepayloading_suite (void)
|
||||||
tcase_add_test (tc_chain, rtp_base_depayload_multiple_exts);
|
tcase_add_test (tc_chain, rtp_base_depayload_multiple_exts);
|
||||||
tcase_add_test (tc_chain, rtp_base_depayload_caps_request_ignored);
|
tcase_add_test (tc_chain, rtp_base_depayload_caps_request_ignored);
|
||||||
tcase_add_test (tc_chain, rtp_base_depayload_hdr_ext_caps_change);
|
tcase_add_test (tc_chain, rtp_base_depayload_hdr_ext_caps_change);
|
||||||
|
tcase_add_test (tc_chain, rtp_base_depayload_hdr_ext_aggregate);
|
||||||
|
tcase_add_test (tc_chain, rtp_base_depayload_hdr_ext_aggregate_drop);
|
||||||
|
tcase_add_test (tc_chain, rtp_base_depayload_hdr_ext_aggregate_delayed);
|
||||||
|
tcase_add_test (tc_chain, rtp_base_depayload_hdr_ext_aggregate_flush);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,6 +199,7 @@ gst_rtp_dummy_hdr_ext_read (GstRTPHeaderExtension * ext,
|
||||||
|
|
||||||
if (dummy->read_count % 5 == 1) {
|
if (dummy->read_count % 5 == 1) {
|
||||||
/* Every fifth buffer triggers caps change. */
|
/* Every fifth buffer triggers caps change. */
|
||||||
|
++dummy->caps_field_value;
|
||||||
gst_rtp_header_extension_set_wants_update_non_rtp_src_caps (ext, TRUE);
|
gst_rtp_header_extension_set_wants_update_non_rtp_src_caps (ext, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +237,7 @@ gst_rtp_dummy_hdr_ext_update_non_rtp_src_caps (GstRTPHeaderExtension * ext,
|
||||||
GstRTPDummyHdrExt *dummy = GST_RTP_DUMMY_HDR_EXT (ext);
|
GstRTPDummyHdrExt *dummy = GST_RTP_DUMMY_HDR_EXT (ext);
|
||||||
|
|
||||||
gst_caps_set_simple (caps, "dummy-hdrext-val", G_TYPE_UINT,
|
gst_caps_set_simple (caps, "dummy-hdrext-val", G_TYPE_UINT,
|
||||||
++dummy->caps_field_value, NULL);
|
dummy->caps_field_value, NULL);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue