From 848a7f2868cc43f748f48f2f9faebdce29b93d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 19 Dec 2009 21:40:44 +0000 Subject: [PATCH 01/21] baseaudiosink: increase default drift tolerance to fix glitches with WMA Increase default drift tolerance to 40ms to avoid glitches with decoders or formats where there's a lot of timestamp jitter for some reason or another (in this case: asf/wma), at least until we implement timestamp smoothing. --- gst-libs/gst/audio/gstbaseaudiosink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/audio/gstbaseaudiosink.c b/gst-libs/gst/audio/gstbaseaudiosink.c index a58e1284bf..fee7c95e37 100644 --- a/gst-libs/gst/audio/gstbaseaudiosink.c +++ b/gst-libs/gst/audio/gstbaseaudiosink.c @@ -88,9 +88,9 @@ enum /* FIXME, enable pull mode when clock slaving and trick modes are figured out */ #define DEFAULT_CAN_ACTIVATE_PULL FALSE -/* when timestamps or clock slaving drift for more than 10ms we resync. This is +/* when timestamps or clock slaving drift for more than 20ms we resync. This is * a reasonable default */ -#define DEFAULT_DRIFT_TOLERANCE ((20 * GST_MSECOND) / GST_USECOND) +#define DEFAULT_DRIFT_TOLERANCE ((40 * GST_MSECOND) / GST_USECOND) enum { From b3c15a340a71afabf416710706e3a9d03bc1cbbe Mon Sep 17 00:00:00 2001 From: David Schleef Date: Sun, 20 Dec 2009 17:34:46 -0800 Subject: [PATCH 02/21] theoraenc: Add encoder controls for libtheora 1.1 Added drop-frames, cap-overflow, cap-underflow, and rate-buffer. --- ext/theora/gsttheoraenc.h | 5 ++ ext/theora/theoraenc.c | 113 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/ext/theora/gsttheoraenc.h b/ext/theora/gsttheoraenc.h index 2514c5657c..3efdab20ab 100644 --- a/ext/theora/gsttheoraenc.h +++ b/ext/theora/gsttheoraenc.h @@ -98,6 +98,11 @@ struct _GstTheoraEnc guint64 timestamp_offset; gint speed_level; + gboolean vp3_compatible; + gboolean drop_frames; + gboolean cap_overflow; + gboolean cap_underflow; + int rate_buffer; }; struct _GstTheoraEncClass diff --git a/ext/theora/theoraenc.c b/ext/theora/theoraenc.c index e735558f7a..121d3820d7 100644 --- a/ext/theora/theoraenc.c +++ b/ext/theora/theoraenc.c @@ -104,6 +104,11 @@ _ilog (unsigned int v) #define THEORA_DEF_KEYFRAME_FREQ 64 #define THEORA_DEF_KEYFRAME_FREQ_FORCE 64 #define THEORA_DEF_SPEEDLEVEL 1 +#define THEORA_DEF_VP3_COMPATIBLE FALSE +#define THEORA_DEF_DROP_FRAMES TRUE +#define THEORA_DEF_CAP_OVERFLOW TRUE +#define THEORA_DEF_CAP_UNDERFLOW FALSE +#define THEORA_DEF_RATE_BUFFER 0 enum { ARG_0, @@ -120,6 +125,11 @@ enum ARG_NOISE_SENSITIVITY, ARG_SHARPNESS, ARG_SPEEDLEVEL, + ARG_VP3_COMPATIBLE, + ARG_DROP_FRAMES, + ARG_CAP_OVERFLOW, + ARG_CAP_UNDERFLOW, + ARG_RATE_BUFFER, /* FILL ME */ }; @@ -273,6 +283,38 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass) "encoding. This property requires libtheora version >= 1.0", 0, 2, THEORA_DEF_SPEEDLEVEL, (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, ARG_VP3_COMPATIBLE, + g_param_spec_boolean ("vp3-compatible", "VP3 Compatible", + "Disables non-VP3 compatible features." + " This property requires libtheora version >= 1.1", + THEORA_DEF_VP3_COMPATIBLE, + (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, ARG_DROP_FRAMES, + g_param_spec_boolean ("drop-frames", "VP3 Compatible", + "Allow or disallow frame dropping." + " This property requires libtheora version >= 1.1", + THEORA_DEF_DROP_FRAMES, + (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, ARG_CAP_OVERFLOW, + g_param_spec_boolean ("cap-overflow", "VP3 Compatible", + "Enable capping of bit reservoir overflows." + " This property requires libtheora version >= 1.1", + THEORA_DEF_CAP_OVERFLOW, + (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, ARG_CAP_UNDERFLOW, + g_param_spec_boolean ("cap-underflow", "VP3 Compatible", + "Enable capping of bit reservoir underflows." + " This property requires libtheora version >= 1.1", + THEORA_DEF_CAP_UNDERFLOW, + (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, ARG_RATE_BUFFER, + g_param_spec_int ("rate-buffer", "Rate Control Buffer", + "Sets the size of the rate control buffer, in units of frames. " + "The default value of 0 instructs the encoder to automatically " + "select an appropriate value." + " This property requires libtheora version >= 1.1", + 0, 1000, THEORA_DEF_RATE_BUFFER, + (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gstelement_class->change_state = theora_enc_change_state; GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder"); @@ -305,6 +347,11 @@ gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class) enc->expected_ts = GST_CLOCK_TIME_NONE; enc->speed_level = THEORA_DEF_SPEEDLEVEL; + enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE; + enc->drop_frames = THEORA_DEF_DROP_FRAMES; + enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW; + enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW; + enc->rate_buffer = THEORA_DEF_RATE_BUFFER; } static void @@ -325,6 +372,7 @@ static void theora_enc_reset (GstTheoraEnc * enc) { ogg_uint32_t keyframe_force; + int rate_flags; if (enc->encoder) th_encode_free (enc->encoder); @@ -335,6 +383,31 @@ theora_enc_reset (GstTheoraEnc * enc) th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level, sizeof (enc->speed_level)); #endif +#ifdef TH_ENCCTL_SET_VP3_COMPATIBLE + th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE, + &enc->vp3_compatible, sizeof (enc->vp3_compatible)); +#endif + + rate_flags = 0; +#ifdef TH_ENCCTL_SET_RATE_FLAGS + if (enc->drop_frames) + rate_flags |= TH_RATECTL_DROP_FRAMES; + if (enc->drop_frames) + rate_flags |= TH_RATECTL_CAP_OVERFLOW; + if (enc->drop_frames) + rate_flags |= TH_RATECTL_CAP_UNDERFLOW; + th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS, + &rate_flags, sizeof (rate_flags)); +#endif + +#ifdef TH_ENCCTL_SET_RATE_BUFFER + if (enc->rate_buffer) { + th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER, + &enc->rate_buffer, sizeof (enc->rate_buffer)); + } else { + /* FIXME */ + } +#endif keyframe_force = enc->keyframe_auto ? enc->keyframe_force : enc->keyframe_freq; @@ -1082,6 +1155,31 @@ theora_enc_set_property (GObject * object, guint prop_id, case ARG_SPEEDLEVEL: #ifdef TH_ENCCTL_SET_SPLEVEL enc->speed_level = g_value_get_int (value); +#endif + break; + case ARG_VP3_COMPATIBLE: +#ifdef TH_ENCCTL_SET_VP3_COMPATIBLE + enc->vp3_compatible = g_value_get_boolean (value); +#endif + break; + case ARG_DROP_FRAMES: +#ifdef TH_ENCCTL_SET_RATE_FLAGS + enc->drop_frames = g_value_get_boolean (value); +#endif + break; + case ARG_CAP_OVERFLOW: +#ifdef TH_ENCCTL_SET_RATE_FLAGS + enc->cap_overflow = g_value_get_boolean (value); +#endif + break; + case ARG_CAP_UNDERFLOW: +#ifdef TH_ENCCTL_SET_RATE_FLAGS + enc->cap_underflow = g_value_get_boolean (value); +#endif + break; + case ARG_RATE_BUFFER: +#ifdef TH_ENCCTL_SET_RATE_BUFFER + enc->rate_buffer = g_value_get_int (value); #endif break; default: @@ -1136,6 +1234,21 @@ theora_enc_get_property (GObject * object, guint prop_id, case ARG_SPEEDLEVEL: g_value_set_int (value, enc->speed_level); break; + case ARG_VP3_COMPATIBLE: + g_value_set_boolean (value, enc->vp3_compatible); + break; + case ARG_DROP_FRAMES: + g_value_set_boolean (value, enc->drop_frames); + break; + case ARG_CAP_OVERFLOW: + g_value_set_boolean (value, enc->cap_overflow); + break; + case ARG_CAP_UNDERFLOW: + g_value_set_boolean (value, enc->cap_underflow); + break; + case ARG_RATE_BUFFER: + g_value_set_int (value, enc->rate_buffer); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; From 6ce1ff2188c9a91cb8d09a2fc3a15cbe8f0fcc95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 21 Dec 2009 07:50:26 +0000 Subject: [PATCH 03/21] tests: don't use deprecated GLib API g_mapped_file_free Fixes #605100. --- tests/examples/app/appsrc-ra.c | 7 ++++++- tests/examples/app/appsrc-seekable.c | 7 ++++++- tests/examples/app/appsrc-stream.c | 7 ++++++- tests/examples/app/appsrc-stream2.c | 7 ++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/tests/examples/app/appsrc-ra.c b/tests/examples/app/appsrc-ra.c index 973dabea78..46b19cae43 100644 --- a/tests/examples/app/appsrc-ra.c +++ b/tests/examples/app/appsrc-ra.c @@ -30,6 +30,11 @@ #include #include +/* FIXME: remove once we depend on GLib >= 2.22 */ +#if !GLIB_CHECK_VERSION (2, 22, 0) +#define g_mapped_file_unref g_mapped_file_free +#endif + GST_DEBUG_CATEGORY (appsrc_playbin_debug); #define GST_CAT_DEFAULT appsrc_playbin_debug @@ -215,7 +220,7 @@ main (int argc, char *argv[]) gst_element_set_state (app->playbin, GST_STATE_NULL); /* free the file */ - g_mapped_file_free (app->file); + g_mapped_file_unref (app->file); gst_object_unref (bus); g_main_loop_unref (app->loop); diff --git a/tests/examples/app/appsrc-seekable.c b/tests/examples/app/appsrc-seekable.c index e09a58e1a2..adff5bb9d5 100644 --- a/tests/examples/app/appsrc-seekable.c +++ b/tests/examples/app/appsrc-seekable.c @@ -30,6 +30,11 @@ #include #include +/* FIXME: remove once we depend on GLib >= 2.22 */ +#if !GLIB_CHECK_VERSION (2, 22, 0) +#define g_mapped_file_unref g_mapped_file_free +#endif + GST_DEBUG_CATEGORY (appsrc_playbin_debug); #define GST_CAT_DEFAULT appsrc_playbin_debug @@ -220,7 +225,7 @@ main (int argc, char *argv[]) gst_element_set_state (app->playbin, GST_STATE_NULL); /* free the file */ - g_mapped_file_free (app->file); + g_mapped_file_unref (app->file); gst_object_unref (bus); g_main_loop_unref (app->loop); diff --git a/tests/examples/app/appsrc-stream.c b/tests/examples/app/appsrc-stream.c index 7038cd3061..ea3286f29a 100644 --- a/tests/examples/app/appsrc-stream.c +++ b/tests/examples/app/appsrc-stream.c @@ -30,6 +30,11 @@ #include #include +/* FIXME: remove once we depend on GLib >= 2.22 */ +#if !GLIB_CHECK_VERSION (2, 22, 0) +#define g_mapped_file_unref g_mapped_file_free +#endif + GST_DEBUG_CATEGORY (appsrc_playbin_debug); #define GST_CAT_DEFAULT appsrc_playbin_debug @@ -240,7 +245,7 @@ main (int argc, char *argv[]) gst_element_set_state (app->playbin, GST_STATE_NULL); /* free the file */ - g_mapped_file_free (app->file); + g_mapped_file_unref (app->file); gst_object_unref (bus); g_main_loop_unref (app->loop); diff --git a/tests/examples/app/appsrc-stream2.c b/tests/examples/app/appsrc-stream2.c index dc1d8caa26..e0c8922a87 100644 --- a/tests/examples/app/appsrc-stream2.c +++ b/tests/examples/app/appsrc-stream2.c @@ -30,6 +30,11 @@ #include #include +/* FIXME: remove once we depend on GLib >= 2.22 */ +#if !GLIB_CHECK_VERSION (2, 22, 0) +#define g_mapped_file_unref g_mapped_file_free +#endif + GST_DEBUG_CATEGORY (appsrc_playbin_debug); #define GST_CAT_DEFAULT appsrc_playbin_debug @@ -210,7 +215,7 @@ main (int argc, char *argv[]) gst_element_set_state (app->playbin, GST_STATE_NULL); /* free the file */ - g_mapped_file_free (app->file); + g_mapped_file_unref (app->file); gst_object_unref (bus); g_main_loop_unref (app->loop); From 98fc463f31d17745f5e754486bb7e235a80d2559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 21 Dec 2009 07:57:42 +0000 Subject: [PATCH 04/21] docs: use 'Returns: xyz' rather than 'Returns xyz' to make gtk-doc happy --- gst-libs/gst/tag/lang.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst-libs/gst/tag/lang.c b/gst-libs/gst/tag/lang.c index 199f99c5e0..2a8cb6fd27 100644 --- a/gst-libs/gst/tag/lang.c +++ b/gst-libs/gst/tag/lang.c @@ -356,7 +356,7 @@ gst_tag_get_language_name (const gchar * language_code) * * Language codes are case-sensitive and expected to be lower case. * - * Returns two-letter ISO-639-1 language code string that maps to @lang_code, + * Returns: two-letter ISO-639-1 language code string that maps to @lang_code, * or NULL if no mapping is known. The returned string must not be * modified or freed. * @@ -438,7 +438,7 @@ gst_tag_get_language_code_iso_639_2X (const gchar * lang_code, guint8 flags) * * Language codes are case-sensitive and expected to be lower case. * - * Returns three-letter ISO-639-2 language code string that maps to @lang_code, + * Returns: three-letter ISO-639-2 language code string that maps to @lang_code, * or NULL if no mapping is known. The returned string must not be * modified or freed. * @@ -474,7 +474,7 @@ gst_tag_get_language_code_iso_639_2T (const gchar * lang_code) * * Language codes are case-sensitive and expected to be lower case. * - * Returns three-letter ISO-639-2 language code string that maps to @lang_code, + * Returns: three-letter ISO-639-2 language code string that maps to @lang_code, * or NULL if no mapping is known. The returned string must not be * modified or freed. * From 93f82f16cdf0ee9fe817cba96b36c4eb6c5cc270 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 21 Dec 2009 18:45:58 +0100 Subject: [PATCH 05/21] audiorate: add Since marker for the new tolerance property --- gst/audiorate/gstaudiorate.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gst/audiorate/gstaudiorate.c b/gst/audiorate/gstaudiorate.c index 2fbd5f8e56..4e6c9bd4d9 100644 --- a/gst/audiorate/gstaudiorate.c +++ b/gst/audiorate/gstaudiorate.c @@ -199,6 +199,14 @@ gst_audio_rate_class_init (GstAudioRateClass * klass) g_param_spec_boolean ("silent", "silent", "Don't emit notify for dropped and duplicated frames", DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstAudioRate:tolerance + * + * The difference between incoming timestamp and next timestamp must exceed + * the given value for audiorate to add or drop samples. + * + * Since: 0.10.26 + **/ g_object_class_install_property (object_class, ARG_TOLERANCE, g_param_spec_uint64 ("tolerance", "tolerance", "Only act if timestamp jitter/imperfection exceeds indicated tolerance (ns)", From 681d23ccb7e2c78b0b582dd548dc0eecbac38813 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 21 Dec 2009 19:12:02 +0100 Subject: [PATCH 06/21] Automatic update of common submodule From 47cb23a to 14cec89 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 47cb23af89..14cec891e9 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 47cb23af8902d358b73d3b60ab9ea4a74d6a114f +Subproject commit 14cec891e98eb39780f67e89a1b821a839c7e370 From f7070b6bc6cbade5b60a2c6ad3441de4010dad43 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 22 Dec 2009 20:15:28 +0100 Subject: [PATCH 07/21] rtcpbuffer: add helper functions for SDES types Add functions to convert SDES names to their types and back. Will be used later to set SDES items using a GstStructure. See #595265 --- docs/libs/gst-plugins-base-libs-sections.txt | 3 + gst-libs/gst/rtp/gstrtcpbuffer.c | 90 ++++++++++++++++++++ gst-libs/gst/rtp/gstrtcpbuffer.h | 3 + 3 files changed, 96 insertions(+) diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt index 7574a4c252..2e96a0a0aa 100644 --- a/docs/libs/gst-plugins-base-libs-sections.txt +++ b/docs/libs/gst-plugins-base-libs-sections.txt @@ -1119,6 +1119,9 @@ gst_rtcp_packet_fb_set_media_ssrc gst_rtcp_ntp_to_unix gst_rtcp_unix_to_ntp +gst_rtcp_sdes_name_to_type +gst_rtcp_sdes_type_to_name + diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.c b/gst-libs/gst/rtp/gstrtcpbuffer.c index e141eb0d66..9177b398ab 100644 --- a/gst-libs/gst/rtp/gstrtcpbuffer.c +++ b/gst-libs/gst/rtp/gstrtcpbuffer.c @@ -1853,3 +1853,93 @@ gst_rtcp_unix_to_ntp (guint64 unixtime) return ntptime; } + +/** + * gst_rtcp_sdes_type_to_name: + * @type: a #GstRTCPSDESType + * + * Converts @type to the string equivalent. The string is typically used as a + * key in a #GstStructure containing SDES items. + * + * Returns: the string equivalent of @type + * + * Since: 0.10.26 + */ +const gchar * +gst_rtcp_sdes_type_to_name (GstRTCPSDESType type) +{ + const gchar *result; + + switch (type) { + case GST_RTCP_SDES_CNAME: + result = "cname"; + break; + case GST_RTCP_SDES_NAME: + result = "name"; + break; + case GST_RTCP_SDES_EMAIL: + result = "email"; + break; + case GST_RTCP_SDES_PHONE: + result = "phone"; + break; + case GST_RTCP_SDES_LOC: + result = "location"; + break; + case GST_RTCP_SDES_TOOL: + result = "tool"; + break; + case GST_RTCP_SDES_NOTE: + result = "note"; + break; + case GST_RTCP_SDES_PRIV: + result = "priv"; + break; + default: + result = NULL; + break; + } + return result; +} + +/** + * gst_rtcp_sdes_name_to_type: + * @name: a SDES name + * + * Convert @name into a @GstRTCPSDESType. @name is typically a key in a + * #GstStructure containing SDES items. + * + * Returns: the #GstRTCPSDESType for @name or #GST_RTCP_SDES_PRIV when @name + * is a private sdes item. + * + * Since: 0.10.26 + */ +GstRTCPSDESType +gst_rtcp_sdes_name_to_type (const gchar * name) +{ + if (name == NULL || strlen (name) == 0) + return GST_RTCP_SDES_INVALID; + + if (strcmp ("cname", name) == 0) + return GST_RTCP_SDES_CNAME; + + if (strcmp ("name", name) == 0) + return GST_RTCP_SDES_NAME; + + if (strcmp ("email", name) == 0) + return GST_RTCP_SDES_EMAIL; + + if (strcmp ("phone", name) == 0) + return GST_RTCP_SDES_PHONE; + + if (strcmp ("location", name) == 0) + return GST_RTCP_SDES_LOC; + + if (strcmp ("tool", name) == 0) + return GST_RTCP_SDES_TOOL; + + if (strcmp ("note", name) == 0) + return GST_RTCP_SDES_NOTE; + + return GST_RTCP_SDES_PRIV; +} diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.h b/gst-libs/gst/rtp/gstrtcpbuffer.h index 75ab4bc72f..b051571fff 100644 --- a/gst-libs/gst/rtp/gstrtcpbuffer.h +++ b/gst-libs/gst/rtp/gstrtcpbuffer.h @@ -274,6 +274,9 @@ void gst_rtcp_packet_fb_set_type (GstRTCPPacket *packet, Gs guint64 gst_rtcp_ntp_to_unix (guint64 ntptime); guint64 gst_rtcp_unix_to_ntp (guint64 unixtime); +const gchar * gst_rtcp_sdes_type_to_name (GstRTCPSDESType type); +GstRTCPSDESType gst_rtcp_sdes_name_to_type (const gchar *name); + G_END_DECLS #endif /* __GST_RTCPBUFFER_H__ */ From 16bc8fe8a1756ad4b30662ddfd3f9a05ff223e51 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 23 Dec 2009 15:30:50 +0100 Subject: [PATCH 08/21] defs: update defs with new symbols --- win32/common/libgstrtp.def | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win32/common/libgstrtp.def b/win32/common/libgstrtp.def index 156d025983..420f6692f4 100644 --- a/win32/common/libgstrtp.def +++ b/win32/common/libgstrtp.def @@ -64,6 +64,8 @@ EXPORTS gst_rtcp_packet_set_rb gst_rtcp_packet_sr_get_sender_info gst_rtcp_packet_sr_set_sender_info + gst_rtcp_sdes_name_to_type + gst_rtcp_sdes_type_to_name gst_rtcp_unix_to_ntp gst_rtp_buffer_allocate_data gst_rtp_buffer_calc_header_len From 138c85117356ad7a558595d168c937461985cad1 Mon Sep 17 00:00:00 2001 From: Jonathan Matthew Date: Wed, 23 Dec 2009 15:43:52 +0100 Subject: [PATCH 09/21] uridecodebin: don't name the queue There is no reason to name the queue. Fixes #605219 --- gst/playback/gsturidecodebin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/playback/gsturidecodebin.c b/gst/playback/gsturidecodebin.c index 5bbbe1fa99..d9f7115539 100644 --- a/gst/playback/gsturidecodebin.c +++ b/gst/playback/gsturidecodebin.c @@ -1076,7 +1076,7 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw, GstPad *sinkpad; /* insert a queue element right before the raw pad */ - outelem = gst_element_factory_make ("queue2", "queue"); + outelem = gst_element_factory_make ("queue2", NULL); gst_bin_add (GST_BIN_CAST (decoder), outelem); sinkpad = gst_element_get_static_pad (outelem, "sink"); From d4e1ff012d285d055598a4b66570c6a33c08dcaa Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 23 Dec 2009 15:46:25 +0100 Subject: [PATCH 10/21] uridecodebin: avoid leaking queue and typefind Don't leak the queue and typefind elements that we might link after the source element. --- gst/playback/gsturidecodebin.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gst/playback/gsturidecodebin.c b/gst/playback/gsturidecodebin.c index d9f7115539..28b985023b 100644 --- a/gst/playback/gsturidecodebin.c +++ b/gst/playback/gsturidecodebin.c @@ -86,6 +86,7 @@ struct _GstURIDecodeBin gboolean use_buffering; GstElement *source; + GstElement *queue; GstElement *typefind; guint have_type_id; /* have-type signal id from typefind */ GSList *decodebins; @@ -1084,6 +1085,9 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw, gst_object_unref (sinkpad); gst_object_unref (pad); + /* save queue pointer so we can remove it later */ + decoder->queue = outelem; + /* get the new raw srcpad */ pad = gst_element_get_static_pad (outelem, "src"); } else { @@ -1482,10 +1486,12 @@ could_not_link: { GST_ELEMENT_ERROR (decoder, CORE, NEGOTIATION, (NULL), ("Can't link source to typefind element")); + gst_bin_remove (GST_BIN_CAST (decoder), typefind); return FALSE; } } +/* remove source and all related elements */ static void remove_source (GstURIDecodeBin * bin) { @@ -1506,6 +1512,18 @@ remove_source (GstURIDecodeBin * bin) } bin->source = NULL; } + if (bin->queue) { + GST_DEBUG_OBJECT (bin, "removing old queue element"); + gst_element_set_state (bin->queue, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (bin), bin->queue); + bin->queue = NULL; + } + if (bin->typefind) { + GST_DEBUG_OBJECT (bin, "removing old typefind element"); + gst_element_set_state (bin->typefind, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (bin), bin->typefind); + bin->typefind = NULL; + } } /* is called when a dynamic source element created a new pad. */ From 3b0fc1e4fb8caaf203b7af0188a0cbed807fc408 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 23 Dec 2009 17:08:27 +0100 Subject: [PATCH 11/21] playbin2: avoid leaking selector request pads --- gst/playback/gstplaybin2.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index d8adb49ccb..a9f71f2e97 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -3182,7 +3182,6 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target) else g_object_set (uridecodebin, "download", FALSE, NULL); - /* configure subtitle encoding */ g_object_set (uridecodebin, "subtitle-encoding", playbin->encoding, NULL); /* configure uri */ @@ -3368,6 +3367,17 @@ deactivate_group (GstPlayBin * playbin, GstSourceGroup * group) } if (select->selector) { + gint n; + + /* release and unref requests pad from the selector */ + for (n = 0; n < select->channels->len; n++) { + GstPad *sinkpad = g_ptr_array_index (select->channels, n); + + gst_element_release_request_pad (select->selector, sinkpad); + gst_object_unref (sinkpad); + } + g_ptr_array_set_size (select->channels, 0); + gst_element_set_state (select->selector, GST_STATE_NULL); gst_bin_remove (GST_BIN_CAST (playbin), select->selector); select->selector = NULL; From 99e836a340a8561e962e2e9962cca3666715092d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 23 Dec 2009 18:18:03 +0100 Subject: [PATCH 12/21] decodebin2: avoid some type checks --- gst/playback/gstdecodebin2.c | 37 ++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index 6f8db2e9ff..b51aa93c75 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -1469,12 +1469,12 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad, "is a demuxer, connecting the pad through multiqueue '%s'", GST_OBJECT_NAME (chain->parent->multiqueue)); - gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), NULL); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (dpad), NULL); if (!(mqpad = gst_decode_group_control_demuxer_pad (chain->parent, pad))) goto beach; src = chain->parent->multiqueue; pad = mqpad; - gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), pad); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (dpad), pad); } /* 2. Try to create an element and link to it */ @@ -1488,7 +1488,7 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad, /* Set dpad target to pad again, it might've been unset * below but we came back here because something failed */ - gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), pad); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (dpad), pad); /* take first factory */ factory = g_value_get_object (g_value_array_get_nth (factories, 0)); @@ -1519,7 +1519,7 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad, } /* 2.0. Unlink pad */ - gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), NULL); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (dpad), NULL); /* 2.1. Try to create an element */ if ((element = gst_element_factory_create (factory, NULL)) == NULL) { @@ -1754,11 +1754,11 @@ expose_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad, if (chain->parent && !chain->elements && src != chain->parent->multiqueue) { GST_LOG_OBJECT (src, "connecting the pad through multiqueue"); - gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), NULL); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (dpad), NULL); if (!(mqpad = gst_decode_group_control_demuxer_pad (chain->parent, pad))) goto beach; pad = mqpad; - gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), pad); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (dpad), pad); } gst_decode_pad_activate (dpad, chain); @@ -2735,8 +2735,8 @@ sort_end_pads (GstDecodePad * da, GstDecodePad * db) GstStructure *sa, *sb; const gchar *namea, *nameb; - capsa = gst_pad_get_caps_reffed (GST_PAD (da)); - capsb = gst_pad_get_caps_reffed (GST_PAD (db)); + capsa = gst_pad_get_caps_reffed (GST_PAD_CAST (da)); + capsb = gst_pad_get_caps_reffed (GST_PAD_CAST (db)); sa = gst_caps_get_structure ((const GstCaps *) capsa, 0); sb = gst_caps_get_structure ((const GstCaps *) capsb, 0); @@ -2987,7 +2987,7 @@ gst_decode_bin_expose (GstDecodeBin * dbin) /* 2. activate and add */ if (!dpad->exposed - && !gst_element_add_pad (GST_ELEMENT (dbin), GST_PAD (dpad))) { + && !gst_element_add_pad (GST_ELEMENT (dbin), GST_PAD_CAST (dpad))) { /* not really fatal, we can try to add the other pads */ g_warning ("error adding pad to decodebin2"); continue; @@ -3162,10 +3162,11 @@ gst_decode_pad_set_blocked (GstDecodePad * dpad, gboolean blocked) gst_pad_set_blocked_async_full (opad, blocked, (GstPadBlockCallback) source_pad_blocked_cb, gst_object_ref (dpad), (GDestroyNotify) gst_object_unref); + if (blocked) { if (dbin->shutdown) { /* deactivate to force flushing state to prevent NOT_LINKED errors */ - gst_pad_set_active (GST_PAD (dpad), FALSE); + gst_pad_set_active (GST_PAD_CAST (dpad), FALSE); } else { gst_object_ref (dpad); dbin->blocked_pads = g_list_prepend (dbin->blocked_pads, dpad); @@ -3186,7 +3187,7 @@ out: static void gst_decode_pad_add_drained_check (GstDecodePad * dpad) { - gst_pad_add_event_probe (GST_PAD (dpad), + gst_pad_add_event_probe (GST_PAD_CAST (dpad), G_CALLBACK (source_pad_event_probe), dpad); } @@ -3196,7 +3197,7 @@ gst_decode_pad_activate (GstDecodePad * dpad, GstDecodeChain * chain) g_return_if_fail (chain != NULL); dpad->chain = chain; - gst_pad_set_active (GST_PAD (dpad), TRUE); + gst_pad_set_active (GST_PAD_CAST (dpad), TRUE); gst_decode_pad_set_blocked (dpad, TRUE); gst_decode_pad_add_drained_check (dpad); } @@ -3216,11 +3217,12 @@ gst_decode_pad_new (GstDecodeBin * dbin, GstPad * pad, GstDecodeChain * chain) { GstDecodePad *dpad; + GST_DEBUG_OBJECT (dbin, "making new decodepad"); dpad = g_object_new (GST_TYPE_DECODE_PAD, "direction", GST_PAD_DIRECTION (pad), NULL); - gst_ghost_pad_construct (GST_GHOST_PAD (dpad)); - gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), pad); + gst_ghost_pad_construct (GST_GHOST_PAD_CAST (dpad)); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (dpad), pad); dpad->chain = chain; dpad->dbin = dbin; @@ -3300,10 +3302,13 @@ unblock_pads (GstDecodeBin * dbin) { GList *tmp; + GST_LOG_OBJECT (dbin, "unblocking pads"); + for (tmp = dbin->blocked_pads; tmp; tmp = tmp->next) { GstDecodePad *dpad = (GstDecodePad *) tmp->data; - GstPad *opad = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (dpad)); + GstPad *opad; + opad = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (dpad)); if (!opad) continue; @@ -3312,7 +3317,7 @@ unblock_pads (GstDecodeBin * dbin) (GstPadBlockCallback) source_pad_blocked_cb, gst_object_ref (dpad), (GDestroyNotify) gst_object_unref); /* make flushing, prevent NOT_LINKED */ - GST_PAD_SET_FLUSHING (GST_PAD (dpad)); + GST_PAD_SET_FLUSHING (GST_PAD_CAST (dpad)); gst_object_unref (dpad); gst_object_unref (opad); GST_DEBUG_OBJECT (dpad, "unblocked"); From 15216d23ac255217612b687f62874e89e66f026a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 23 Dec 2009 21:24:48 +0100 Subject: [PATCH 13/21] decodebin2: fix typo in debug message --- gst/playback/gstdecodebin2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index b51aa93c75..eeb1e9e902 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -2190,7 +2190,7 @@ gst_decode_chain_free_internal (GstDecodeChain * chain, gboolean hide) chain->endcaps = NULL; } - GST_DEBUG_OBJECT (chain->dbin, "%s chain %p", (hide ? "Hided" : "Freed"), + GST_DEBUG_OBJECT (chain->dbin, "%s chain %p", (hide ? "Hidden" : "Freed"), chain); CHAIN_MUTEX_UNLOCK (chain); if (!hide) { From 66ae01ecedcf61401a36127c53dcfac6de0d25b6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 24 Dec 2009 13:58:52 +0100 Subject: [PATCH 14/21] adder: fix juvenile comment --- gst/adder/gstadder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/adder/gstadder.c b/gst/adder/gstadder.c index 1d17d0bfc0..af0e472b17 100644 --- a/gst/adder/gstadder.c +++ b/gst/adder/gstadder.c @@ -798,7 +798,7 @@ gst_adder_sink_event (GstPad * pad, GstEvent * event) break; case GST_EVENT_TAG: GST_OBJECT_LOCK (adder->collect); - /* collectpads is a pile of horse manure. */ + /* collect tags here so we can push them out when we collect data */ adder->pending_events = g_list_append (adder->pending_events, event); GST_OBJECT_UNLOCK (adder->collect); goto beach; From 59ace1b9ee9015f0035e32366296b6c6dd199155 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 24 Dec 2009 16:30:23 +0100 Subject: [PATCH 15/21] adder: use collectpads clipping function Install a clipping function in the collectpads and use the audio clipping helper function to perform clipping to the segment boundaries. Fixes #590265 --- gst/adder/Makefile.am | 6 +- gst/adder/gstadder.c | 18 +++++- tests/check/elements/adder.c | 111 +++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 3 deletions(-) diff --git a/gst/adder/Makefile.am b/gst/adder/Makefile.am index cf4005d07d..7ec0a40e24 100644 --- a/gst/adder/Makefile.am +++ b/gst/adder/Makefile.am @@ -1,10 +1,12 @@ plugin_LTLIBRARIES = libgstadder.la libgstadder_la_SOURCES = gstadder.c -libgstadder_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstadder_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) #$(LIBOIL_CFLAGS) libgstadder_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstadder_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) +libgstadder_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \ + $(GST_BASE_LIBS) $(GST_LIBS) #$(LIBOIL_LIBS) libgstadder_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/gst/adder/gstadder.c b/gst/adder/gstadder.c index af0e472b17..4fe9739468 100644 --- a/gst/adder/gstadder.c +++ b/gst/adder/gstadder.c @@ -136,6 +136,8 @@ static void gst_adder_release_pad (GstElement * element, GstPad * pad); static GstStateChangeReturn gst_adder_change_state (GstElement * element, GstStateChange transition); +static GstBuffer *gst_adder_do_clip (GstCollectPads * pads, + GstCollectData * data, GstBuffer * buffer, gpointer user_data); static GstFlowReturn gst_adder_collected (GstCollectPads * pads, gpointer user_data); @@ -780,7 +782,7 @@ gst_adder_sink_event (GstPad * pad, GstEvent * event) case GST_EVENT_FLUSH_STOP: /* we received a flush-stop. The collect_event function will push the * event past our element. We simply forward all flush-stop events, even - * when no flush-stop was pendingk, this is required because collectpads + * when no flush-stop was pending, this is required because collectpads * does not provide an API to handle-but-not-forward the flush-stop. * We unset the pending flush-stop flag so that we don't send anymore * flush-stop from the collect function later. @@ -882,6 +884,8 @@ gst_adder_init (GstAdder * adder) adder->collect = gst_collect_pads_new (); gst_collect_pads_set_function (adder->collect, GST_DEBUG_FUNCPTR (gst_adder_collected), adder); + gst_collect_pads_set_clip_function (adder->collect, + GST_DEBUG_FUNCPTR (gst_adder_do_clip), adder); } static void @@ -1023,6 +1027,18 @@ gst_adder_release_pad (GstElement * element, GstPad * pad) gst_element_remove_pad (element, pad); } +static GstBuffer * +gst_adder_do_clip (GstCollectPads * pads, GstCollectData * data, + GstBuffer * buffer, gpointer user_data) +{ + GstAdder *adder = GST_ADDER (user_data); + + buffer = gst_audio_buffer_clip (buffer, &data->segment, adder->rate, + adder->bps); + + return buffer; +} + static GstFlowReturn gst_adder_collected (GstCollectPads * pads, gpointer user_data) { diff --git a/tests/check/elements/adder.c b/tests/check/elements/adder.c index 243e3b68f8..db0e79acf5 100644 --- a/tests/check/elements/adder.c +++ b/tests/check/elements/adder.c @@ -732,6 +732,116 @@ GST_START_TEST (test_remove_pad) GST_END_TEST; +static GstBuffer *handoff_buffer = NULL; +static void +handoff_buffer_cb (GstElement * fakesink, GstBuffer * buffer, GstPad * pad, + gpointer user_data) +{ + GST_DEBUG ("got buffer %p", buffer); + gst_buffer_replace (&handoff_buffer, buffer); +} + +/* check if clipping works as expected */ +GST_START_TEST (test_clip) +{ + GstElement *bin, *adder, *sink; + GstBus *bus; + GstPad *sinkpad; + gboolean res; + GstFlowReturn ret; + GstEvent *event; + GstBuffer *buffer; + GstCaps *caps; + + GST_INFO ("preparing test"); + + /* build pipeline */ + bin = gst_pipeline_new ("pipeline"); + bus = gst_element_get_bus (bin); + gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH); + + g_signal_connect (bus, "message::error", (GCallback) message_received, bin); + g_signal_connect (bus, "message::warning", (GCallback) message_received, bin); + g_signal_connect (bus, "message::eos", (GCallback) message_received, bin); + + /* just an adder and a fakesink */ + adder = gst_element_factory_make ("adder", "adder"); + sink = gst_element_factory_make ("fakesink", "sink"); + g_object_set (sink, "signal-handoffs", TRUE, NULL); + g_signal_connect (sink, "handoff", (GCallback) handoff_buffer_cb, NULL); + gst_bin_add_many (GST_BIN (bin), adder, sink, NULL); + + res = gst_element_link (adder, sink); + fail_unless (res == TRUE, NULL); + + /* set to playing */ + res = gst_element_set_state (bin, GST_STATE_PLAYING); + fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL); + + /* create an unconnected sinkpad in adder, should also automatically activate + * the pad */ + sinkpad = gst_element_get_request_pad (adder, "sink%d"); + fail_if (sinkpad == NULL, NULL); + + /* send segment to adder */ + event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, + GST_SECOND, 2 * GST_SECOND, 0); + gst_pad_send_event (sinkpad, event); + + caps = gst_caps_new_simple ("audio/x-raw-int", + "rate", G_TYPE_INT, 44100, + "channels", G_TYPE_INT, 2, + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL); + + /* should be clipped and ok */ + buffer = gst_buffer_new_and_alloc (44100); + GST_BUFFER_TIMESTAMP (buffer) = 0; + GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; + gst_buffer_set_caps (buffer, caps); + GST_DEBUG ("pushing buffer %p", buffer); + ret = gst_pad_chain (sinkpad, buffer); + fail_unless (ret == GST_FLOW_OK); + fail_unless (handoff_buffer == NULL); + + /* should be partially clipped */ + buffer = gst_buffer_new_and_alloc (44100); + GST_BUFFER_TIMESTAMP (buffer) = 900 * GST_MSECOND; + GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; + gst_buffer_set_caps (buffer, caps); + GST_DEBUG ("pushing buffer %p", buffer); + ret = gst_pad_chain (sinkpad, buffer); + fail_unless (ret == GST_FLOW_OK); + fail_unless (handoff_buffer != NULL); + gst_buffer_replace (&handoff_buffer, NULL); + + /* should not be clipped */ + buffer = gst_buffer_new_and_alloc (44100); + GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND; + GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; + gst_buffer_set_caps (buffer, caps); + GST_DEBUG ("pushing buffer %p", buffer); + ret = gst_pad_chain (sinkpad, buffer); + fail_unless (ret == GST_FLOW_OK); + fail_unless (handoff_buffer != NULL); + gst_buffer_replace (&handoff_buffer, NULL); + + /* should be clipped and ok */ + buffer = gst_buffer_new_and_alloc (44100); + GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND; + GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; + gst_buffer_set_caps (buffer, caps); + GST_DEBUG ("pushing buffer %p", buffer); + ret = gst_pad_chain (sinkpad, buffer); + fail_unless (ret == GST_FLOW_OK); + fail_unless (handoff_buffer == NULL); + + +} + +GST_END_TEST; + static Suite * adder_suite (void) { @@ -745,6 +855,7 @@ adder_suite (void) tcase_add_test (tc_chain, test_live_seeking); tcase_add_test (tc_chain, test_add_pad); tcase_add_test (tc_chain, test_remove_pad); + tcase_add_test (tc_chain, test_clip); /* Use a longer timeout */ #ifdef HAVE_VALGRIND From 775636e7341c31c86a5871c395d3472fe0f06ed8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 24 Dec 2009 19:56:55 +0100 Subject: [PATCH 16/21] adder: be a lot smarter with buffer management Detect EOS faster. Try to reuse one of the input buffer as the output buffer. This usually works and avoids an allocation and a memcpy. Be smarter with GAP buffers so that they don't get mixed or cleared at all. Also try to use a GAP buffer as the output buffer when all input buffers are GAP buffers. --- gst/adder/gstadder.c | 109 ++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/gst/adder/gstadder.c b/gst/adder/gstadder.c index 4fe9739468..4dc9fd42e8 100644 --- a/gst/adder/gstadder.c +++ b/gst/adder/gstadder.c @@ -1059,12 +1059,11 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) * mix into a temp (float) buffer and scale afterwards as well */ GstAdder *adder; - GSList *collected; + GSList *collected, *next = NULL; GstFlowReturn ret; - GstBuffer *outbuf = NULL; + GstBuffer *outbuf = NULL, *gapbuf = NULL; gpointer outdata = NULL; guint outsize; - gboolean empty = TRUE; adder = GST_ADDER (user_data); @@ -1080,20 +1079,26 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) /* get available bytes for reading, this can be 0 which could mean empty * buffers or EOS, which we will catch when we loop over the pads. */ outsize = gst_collect_pads_available (pads); + /* can only happen when no pads to collect or all EOS */ + if (outsize == 0) + goto eos; GST_LOG_OBJECT (adder, "starting to cycle through channels, %d bytes available (bps = %d)", outsize, adder->bps); - for (collected = pads->data; collected; collected = g_slist_next (collected)) { + for (collected = pads->data; collected; collected = next) { GstCollectData *collect_data; GstBuffer *inbuf; - guint8 *indata; - guint insize; + gboolean is_gap; + + /* take next to see if this is the last collectdata */ + next = g_slist_next (collected); collect_data = (GstCollectData *) collected->data; - /* get a subbuffer of size bytes */ + /* get a buffer of size bytes, if we get a buffer, it is at least outsize + * bytes big. */ inbuf = gst_collect_pads_take_buffer (pads, collect_data, outsize); /* NULL means EOS or an empty buffer so we still need to flush in * case of an empty buffer. */ @@ -1102,55 +1107,69 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) continue; } - indata = GST_BUFFER_DATA (inbuf); - insize = GST_BUFFER_SIZE (inbuf); + is_gap = GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP); + /* Try to make an output buffer */ if (outbuf == NULL) { - GST_LOG_OBJECT (adder, "channel %p: making output buffer of %d bytes", - collect_data, outsize); + /* if this is a gap buffer but we have some more pads to check, skip it. + * If we are at the last buffer, take it, regardless if it is a GAP + * buffer or not. */ + if (is_gap && next) { + GST_DEBUG_OBJECT (adder, "skipping, non-last GAP buffer"); + /* we keep the GAP buffer, if we don't have anymore buffers (all pads + * EOS, we can use this one as the output buffer. */ + if (gapbuf == NULL) + gapbuf = inbuf; + else + gst_buffer_unref (inbuf); + continue; + } - /* first buffer, alloc outsize. - * FIXME: we can easily subbuffer and _make_writable. - * FIXME: only create empty buffer for first non-gap buffer, so that we - * only use adder function when really adding - */ - outbuf = gst_buffer_new_and_alloc (outsize); + GST_LOG_OBJECT (adder, "channel %p: preparing output buffer of %d bytes", + collect_data, outsize); + /* make data and metadata writable, can simply return the inbuf when we + * are the only one referencing this buffer. If this is the last (and + * only) GAP buffer, it will automatically copy the GAP flag. */ + outbuf = gst_buffer_make_writable (inbuf); outdata = GST_BUFFER_DATA (outbuf); gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad)); - - if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) { - GST_LOG_OBJECT (adder, "channel %p: copying %d bytes from data %p", - collect_data, insize, indata); - /* clear if we are only going to fill a partial buffer */ - if (G_UNLIKELY (outsize > insize)) - memset ((guint8 *) outdata + insize, 0, outsize - insize); - /* and copy the data into it */ - memcpy (outdata, indata, insize); - empty = FALSE; - } else { - /* clear whole buffer */ - GST_LOG_OBJECT (adder, "channel %p: zeroing %d bytes from data %p", - collect_data, insize, indata); - memset (outdata, 0, outsize); - } } else { - if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) { + if (!is_gap) { + /* we had a previous output buffer, mix this non-GAP buffer */ + guint8 *indata; + guint insize; + + indata = GST_BUFFER_DATA (inbuf); + insize = GST_BUFFER_SIZE (inbuf); + + /* all buffers should have outsize, there are no short buffers because we + * asked for the max size above */ + g_assert (insize == outsize); + GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p", collect_data, insize, indata); + /* further buffers, need to add them */ adder->func ((gpointer) outdata, (gpointer) indata, insize); - empty = FALSE; } else { - GST_LOG_OBJECT (adder, "channel %p: skipping %d bytes from data %p", - collect_data, insize, indata); + /* skip gap buffer */ + GST_LOG_OBJECT (adder, "channel %p: skipping GAP buffer", collect_data); } + gst_buffer_unref (inbuf); } - gst_buffer_unref (inbuf); } - /* can only happen when no pads to collect or all EOS */ - if (outbuf == NULL) - goto eos; + if (outbuf == NULL) { + /* no output buffer, reuse one of the GAP buffers then if we have one */ + if (gapbuf) { + GST_LOG_OBJECT (adder, "reusing GAP buffer %p", gapbuf); + outbuf = gapbuf; + } else + /* assume EOS otherwise, this should not happen, really */ + goto eos; + } else if (gapbuf) + /* we had an output buffer, unref the gapbuffer we kept */ + gst_buffer_unref (gapbuf); /* our timestamping is very simple, just an ever incrementing * counter, the new segment time will take care of their respective @@ -1215,13 +1234,9 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) GST_BUFFER_DURATION (outbuf) = adder->timestamp - GST_BUFFER_TIMESTAMP (outbuf); - /* if we only processed silence, mark output again as silence */ - if (empty) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); - /* send it out */ - GST_LOG_OBJECT (adder, "pushing outbuf, timestamp %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); + GST_LOG_OBJECT (adder, "pushing outbuf %p, timestamp %" GST_TIME_FORMAT, + outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); ret = gst_pad_push (adder->srcpad, outbuf); GST_LOG_OBJECT (adder, "pushed outbuf, result = %s", gst_flow_get_name (ret)); From 133e1cdb566fdb7b183aadce9bf33e81cb25b4bd Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sat, 26 Dec 2009 18:46:50 +0100 Subject: [PATCH 17/21] audiorate: correctly eat empty and dummy buffers --- gst/audiorate/gstaudiorate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/audiorate/gstaudiorate.c b/gst/audiorate/gstaudiorate.c index 4e6c9bd4d9..0adf8e18be 100644 --- a/gst/audiorate/gstaudiorate.c +++ b/gst/audiorate/gstaudiorate.c @@ -672,10 +672,10 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) } } +send: if (GST_BUFFER_SIZE (buf) == 0) goto beach; -send: /* Now calculate parameters for whichever buffer (either the original * or truncated one) we're pushing. */ GST_BUFFER_OFFSET (buf) = audiorate->next_offset; From 234b18965de6ef5d4457a30ef0d114688b1eef9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 26 Dec 2009 23:29:24 +0000 Subject: [PATCH 18/21] tests: fix warning and memory leak in stress-overlay test Not all messages have structures and we need to unref messages when returning GST_BUS_DROP in the sync bus handler. --- tests/icles/stress-xoverlay.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/icles/stress-xoverlay.c b/tests/icles/stress-xoverlay.c index 41a6c923b6..4a7a3c7a2d 100644 --- a/tests/icles/stress-xoverlay.c +++ b/tests/icles/stress-xoverlay.c @@ -146,7 +146,7 @@ create_window (GstBus * bus, GstMessage * message, GstPipeline * pipeline) GstXOverlay *ov = NULL; s = gst_message_get_structure (message); - if (!gst_structure_has_name (s, "prepare-xwindow-id")) { + if (s == NULL || !gst_structure_has_name (s, "prepare-xwindow-id")) { return GST_BUS_PASS; } @@ -161,6 +161,7 @@ create_window (GstBus * bus, GstMessage * message, GstPipeline * pipeline) g_timeout_add (100, (GSourceFunc) cycle_window, ov); g_timeout_add (2000, (GSourceFunc) toggle_events, ov); + gst_message_unref (message); return GST_BUS_DROP; } From f82ac8bf44120bd7b19438cb1a505a8dd1029c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 29 Dec 2009 00:40:27 +0000 Subject: [PATCH 19/21] examples: make seek example work with Gtk+ >= 2.18 Gtk+ broke API slightly with the introduction of client-side windows in Gtk+ 2.18. Fix up seek example to work with newer Gtk+ versions. Fixes #601809. --- tests/examples/seek/seek.c | 47 +++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/tests/examples/seek/seek.c b/tests/examples/seek/seek.c index 19b8ab6ce3..7bdc5b8616 100644 --- a/tests/examples/seek/seek.c +++ b/tests/examples/seek/seek.c @@ -2391,8 +2391,13 @@ msg_clock_lost (GstBus * bus, GstMessage * message, GstPipeline * data) #ifdef HAVE_X -static guint embed_xid = 0; +static gulong embed_xid = 0; +/* We set the xid here in response to the prepare-xwindow-id message via a + * bus sync handler because we don't know the actual videosink used from the + * start (as we don't know the pipeline, or bin elements such as autovideosink + * or gconfvideosink may be used which create the actual videosink only once + * the pipeline is started) */ static GstBusSyncReply bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data) { @@ -2400,18 +2405,21 @@ bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data) gst_structure_has_name (message->structure, "prepare-xwindow-id")) { GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message)); - g_print ("got prepare-xwindow-id\n"); - if (!embed_xid) { - embed_xid = GDK_WINDOW_XID (GDK_WINDOW (video_window->window)); - } + g_print ("got prepare-xwindow-id, setting XID %lu\n", embed_xid); if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), "force-aspect-ratio")) { g_object_set (element, "force-aspect-ratio", TRUE, NULL); } - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - embed_xid); + /* Should have been initialised from main thread before (can't use + * GDK_WINDOW_XID here with Gtk+ >= 2.18, because the sync handler will + * be called from a streaming thread and GDK_WINDOW_XID maps to more than + * a simple structure lookup with Gtk+ >= 2.18, where 'more' is stuff that + * shouldn't be done from a non-GUI thread without explicit locking). */ + g_assert (embed_xid != 0); + + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (element), embed_xid); } return GST_BUS_PASS; } @@ -2427,6 +2435,19 @@ handle_expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) return FALSE; } +static void +realize_cb (GtkWidget * widget, gpointer data) +{ + /* This is here just for pedagogical purposes, GDK_WINDOW_XID will call it + * as well */ + if (!gdk_window_ensure_native (widget->window)) + g_error ("Couldn't create native window needed for GstXOverlay!"); + +#ifdef HAVE_X + embed_xid = GDK_WINDOW_XID (video_window->window); + g_print ("Window realize: video window XID = %lu\n", embed_xid); +#endif +} static void msg_eos (GstBus * bus, GstMessage * message, GstPipeline * data) @@ -2623,9 +2644,11 @@ main (int argc, char **argv) /* initialize gui elements ... */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); video_window = gtk_drawing_area_new (); - g_signal_connect (G_OBJECT (video_window), "expose-event", + g_signal_connect (video_window, "expose-event", G_CALLBACK (handle_expose_cb), NULL); + g_signal_connect (video_window, "realize", G_CALLBACK (realize_cb), NULL); gtk_widget_set_double_buffered (video_window, FALSE); + statusbar = gtk_statusbar_new (); status_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), "seek"); gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stopped"); @@ -2891,6 +2914,14 @@ main (int argc, char **argv) /* show the gui. */ gtk_widget_show_all (window); + /* realize window now so that the video window gets created and we can + * obtain its XID before the pipeline is started up and the videosink + * asks for the XID of the window to render onto */ + gtk_widget_realize (window); + + /* we should have the XID now */ + g_assert (embed_xid != 0); + if (verbose) { g_signal_connect (pipeline, "deep_notify", G_CALLBACK (gst_object_default_deep_notify), NULL); From 7388401f935fb3b0bb3212b18ae55521fec31d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 29 Dec 2009 00:53:53 +0000 Subject: [PATCH 20/21] tests: fix colorkey test up for Gtk+ >= 2.18 Make test-colorkey work with newer versions of Gtk+. See #601809. --- tests/icles/test-colorkey.c | 64 ++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/tests/icles/test-colorkey.c b/tests/icles/test-colorkey.c index b0ba42a576..e51d36330b 100644 --- a/tests/icles/test-colorkey.c +++ b/tests/icles/test-colorkey.c @@ -38,32 +38,9 @@ static GtkWidget *video_window = NULL; static GstElement *sink = NULL; -static guint embed_xid = 0; +static gulong embed_xid = 0; static GdkGC *trans_gc = NULL; -static GstBusSyncReply -bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * pipeline) -{ - if ((GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) && - gst_structure_has_name (message->structure, "prepare-xwindow-id")) { - GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message)); - - g_print ("got prepare-xwindow-id\n"); - if (!embed_xid) { - embed_xid = GDK_WINDOW_XID (GDK_WINDOW (video_window->window)); - } - - if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), - "force-aspect-ratio")) { - g_object_set (element, "force-aspect-ratio", TRUE, NULL); - } - - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - embed_xid); - } - return GST_BUS_PASS; -} - static void redraw_overlay (GtkWidget * widget) { @@ -101,6 +78,18 @@ handle_expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) return FALSE; } +static void +realize_cb (GtkWidget * widget, gpointer data) +{ + /* This is here just for pedagogical purposes, GDK_WINDOW_XID will call it + * as well */ + if (!gdk_window_ensure_native (widget->window)) + g_error ("Couldn't create native window needed for GstXOverlay!"); + + embed_xid = GDK_WINDOW_XID (video_window->window); + g_print ("Window realize: got XID %lu\n", embed_xid); +} + static void msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline) { @@ -192,13 +181,16 @@ main (int argc, char **argv) gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); gst_element_link (src, sink); - g_object_set (G_OBJECT (sink), "autopaint-colorkey", FALSE, "force-aspect-ratio", TRUE, "draw-borders", FALSE, "colorkey", 0x7F7F7F, /* gray */ - NULL); +#define COLOR_GRAY 0x7F7F7F + + g_object_set (G_OBJECT (sink), "autopaint-colorkey", FALSE, + "force-aspect-ratio", TRUE, "draw-borders", FALSE, + "colorkey", COLOR_GRAY, NULL); /* check xvimagesink capabilities */ sret = gst_element_set_state (pipeline, GST_STATE_READY); if (sret == GST_STATE_CHANGE_FAILURE) { - g_printerr ("Can't set pipelien to READY\n"); + g_printerr ("Can't set pipeline to READY\n"); gst_object_unref (pipeline); return -1; } @@ -223,8 +215,6 @@ main (int argc, char **argv) g_value_array_free (arr); bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, - pipeline); gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH); g_signal_connect (bus, "message::state-changed", G_CALLBACK (msg_state_changed), pipeline); @@ -242,12 +232,28 @@ main (int argc, char **argv) G_CALLBACK (handle_resize_cb), NULL); g_signal_connect (G_OBJECT (video_window), "expose-event", G_CALLBACK (handle_expose_cb), NULL); + g_signal_connect (video_window, "realize", G_CALLBACK (realize_cb), NULL); gtk_widget_set_double_buffered (video_window, FALSE); gtk_container_add (GTK_CONTAINER (window), video_window); /* show the gui and play */ gtk_widget_show_all (window); + + /* realize window now so that the video window gets created and we can + * obtain its XID before the pipeline is started up and the videosink + * asks for the XID of the window to render onto */ + gtk_widget_realize (window); + + /* we should have the XID now */ + g_assert (embed_xid != 0); + + /* we know what the video sink is in this case (xvimagesink), so we can + * just set it directly here now (instead of waiting for a prepare-xwindow-id + * element message in a sync bus handler and setting it there) */ + g_print ("setting XID %lu\n", embed_xid); + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (sink), embed_xid); + g_idle_add (start_pipeline, pipeline); gtk_main (); From fe970cb8566b3b7e24d9e2786738f5273f089af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 4 Jan 2010 09:49:25 +0000 Subject: [PATCH 21/21] examples: use Gtk+-2.18 API conditionally so the seek example and colorkey test work with older Gtk+ versions as well. Fixes #605960. --- tests/examples/seek/seek.c | 2 ++ tests/icles/test-colorkey.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/examples/seek/seek.c b/tests/examples/seek/seek.c index 7bdc5b8616..405e00edd1 100644 --- a/tests/examples/seek/seek.c +++ b/tests/examples/seek/seek.c @@ -2438,10 +2438,12 @@ handle_expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) static void realize_cb (GtkWidget * widget, gpointer data) { +#if GTK_CHECK_VERSION(2,18,0) /* This is here just for pedagogical purposes, GDK_WINDOW_XID will call it * as well */ if (!gdk_window_ensure_native (widget->window)) g_error ("Couldn't create native window needed for GstXOverlay!"); +#endif #ifdef HAVE_X embed_xid = GDK_WINDOW_XID (video_window->window); diff --git a/tests/icles/test-colorkey.c b/tests/icles/test-colorkey.c index e51d36330b..9acab17780 100644 --- a/tests/icles/test-colorkey.c +++ b/tests/icles/test-colorkey.c @@ -81,10 +81,12 @@ handle_expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) static void realize_cb (GtkWidget * widget, gpointer data) { +#if GTK_CHECK_VERSION(2,18,0) /* This is here just for pedagogical purposes, GDK_WINDOW_XID will call it * as well */ if (!gdk_window_ensure_native (widget->window)) g_error ("Couldn't create native window needed for GstXOverlay!"); +#endif embed_xid = GDK_WINDOW_XID (video_window->window); g_print ("Window realize: got XID %lu\n", embed_xid);