mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
Merge branch 'master' of ssh://git.freedesktop.org/git/gstreamer/gst-plugins-base
This commit is contained in:
commit
22939b074c
23 changed files with 582 additions and 119 deletions
2
common
2
common
|
@ -1 +1 @@
|
||||||
Subproject commit 47cb23af8902d358b73d3b60ab9ea4a74d6a114f
|
Subproject commit 14cec891e98eb39780f67e89a1b821a839c7e370
|
|
@ -1119,6 +1119,9 @@ gst_rtcp_packet_fb_set_media_ssrc
|
||||||
gst_rtcp_ntp_to_unix
|
gst_rtcp_ntp_to_unix
|
||||||
gst_rtcp_unix_to_ntp
|
gst_rtcp_unix_to_ntp
|
||||||
|
|
||||||
|
gst_rtcp_sdes_name_to_type
|
||||||
|
gst_rtcp_sdes_type_to_name
|
||||||
|
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,11 @@ struct _GstTheoraEnc
|
||||||
guint64 timestamp_offset;
|
guint64 timestamp_offset;
|
||||||
|
|
||||||
gint speed_level;
|
gint speed_level;
|
||||||
|
gboolean vp3_compatible;
|
||||||
|
gboolean drop_frames;
|
||||||
|
gboolean cap_overflow;
|
||||||
|
gboolean cap_underflow;
|
||||||
|
int rate_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstTheoraEncClass
|
struct _GstTheoraEncClass
|
||||||
|
|
|
@ -104,6 +104,11 @@ _ilog (unsigned int v)
|
||||||
#define THEORA_DEF_KEYFRAME_FREQ 64
|
#define THEORA_DEF_KEYFRAME_FREQ 64
|
||||||
#define THEORA_DEF_KEYFRAME_FREQ_FORCE 64
|
#define THEORA_DEF_KEYFRAME_FREQ_FORCE 64
|
||||||
#define THEORA_DEF_SPEEDLEVEL 1
|
#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
|
enum
|
||||||
{
|
{
|
||||||
ARG_0,
|
ARG_0,
|
||||||
|
@ -120,6 +125,11 @@ enum
|
||||||
ARG_NOISE_SENSITIVITY,
|
ARG_NOISE_SENSITIVITY,
|
||||||
ARG_SHARPNESS,
|
ARG_SHARPNESS,
|
||||||
ARG_SPEEDLEVEL,
|
ARG_SPEEDLEVEL,
|
||||||
|
ARG_VP3_COMPATIBLE,
|
||||||
|
ARG_DROP_FRAMES,
|
||||||
|
ARG_CAP_OVERFLOW,
|
||||||
|
ARG_CAP_UNDERFLOW,
|
||||||
|
ARG_RATE_BUFFER,
|
||||||
/* FILL ME */
|
/* FILL ME */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -273,6 +283,38 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass)
|
||||||
"encoding. This property requires libtheora version >= 1.0",
|
"encoding. This property requires libtheora version >= 1.0",
|
||||||
0, 2, THEORA_DEF_SPEEDLEVEL,
|
0, 2, THEORA_DEF_SPEEDLEVEL,
|
||||||
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
(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;
|
gstelement_class->change_state = theora_enc_change_state;
|
||||||
GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
|
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->expected_ts = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
enc->speed_level = THEORA_DEF_SPEEDLEVEL;
|
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
|
static void
|
||||||
|
@ -325,6 +372,7 @@ static void
|
||||||
theora_enc_reset (GstTheoraEnc * enc)
|
theora_enc_reset (GstTheoraEnc * enc)
|
||||||
{
|
{
|
||||||
ogg_uint32_t keyframe_force;
|
ogg_uint32_t keyframe_force;
|
||||||
|
int rate_flags;
|
||||||
|
|
||||||
if (enc->encoder)
|
if (enc->encoder)
|
||||||
th_encode_free (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,
|
th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
|
||||||
sizeof (enc->speed_level));
|
sizeof (enc->speed_level));
|
||||||
#endif
|
#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 ?
|
keyframe_force = enc->keyframe_auto ?
|
||||||
enc->keyframe_force : enc->keyframe_freq;
|
enc->keyframe_force : enc->keyframe_freq;
|
||||||
|
@ -1082,6 +1155,31 @@ theora_enc_set_property (GObject * object, guint prop_id,
|
||||||
case ARG_SPEEDLEVEL:
|
case ARG_SPEEDLEVEL:
|
||||||
#ifdef TH_ENCCTL_SET_SPLEVEL
|
#ifdef TH_ENCCTL_SET_SPLEVEL
|
||||||
enc->speed_level = g_value_get_int (value);
|
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
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1136,6 +1234,21 @@ theora_enc_get_property (GObject * object, guint prop_id,
|
||||||
case ARG_SPEEDLEVEL:
|
case ARG_SPEEDLEVEL:
|
||||||
g_value_set_int (value, enc->speed_level);
|
g_value_set_int (value, enc->speed_level);
|
||||||
break;
|
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:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -88,9 +88,9 @@ enum
|
||||||
/* FIXME, enable pull mode when clock slaving and trick modes are figured out */
|
/* FIXME, enable pull mode when clock slaving and trick modes are figured out */
|
||||||
#define DEFAULT_CAN_ACTIVATE_PULL FALSE
|
#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 */
|
* a reasonable default */
|
||||||
#define DEFAULT_DRIFT_TOLERANCE ((20 * GST_MSECOND) / GST_USECOND)
|
#define DEFAULT_DRIFT_TOLERANCE ((40 * GST_MSECOND) / GST_USECOND)
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
|
|
@ -1853,3 +1853,93 @@ gst_rtcp_unix_to_ntp (guint64 unixtime)
|
||||||
|
|
||||||
return ntptime;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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_ntp_to_unix (guint64 ntptime);
|
||||||
guint64 gst_rtcp_unix_to_ntp (guint64 unixtime);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_RTCPBUFFER_H__ */
|
#endif /* __GST_RTCPBUFFER_H__ */
|
||||||
|
|
|
@ -356,7 +356,7 @@ gst_tag_get_language_name (const gchar * language_code)
|
||||||
*
|
*
|
||||||
* Language codes are case-sensitive and expected to be lower case.
|
* 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
|
* or NULL if no mapping is known. The returned string must not be
|
||||||
* modified or freed.
|
* 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.
|
* 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
|
* or NULL if no mapping is known. The returned string must not be
|
||||||
* modified or freed.
|
* 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.
|
* 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
|
* or NULL if no mapping is known. The returned string must not be
|
||||||
* modified or freed.
|
* modified or freed.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
plugin_LTLIBRARIES = libgstadder.la
|
plugin_LTLIBRARIES = libgstadder.la
|
||||||
|
|
||||||
libgstadder_la_SOURCES = gstadder.c
|
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)
|
#$(LIBOIL_CFLAGS)
|
||||||
libgstadder_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
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)
|
#$(LIBOIL_LIBS)
|
||||||
libgstadder_la_LIBTOOLFLAGS = --tag=disable-static
|
libgstadder_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,8 @@ static void gst_adder_release_pad (GstElement * element, GstPad * pad);
|
||||||
static GstStateChangeReturn gst_adder_change_state (GstElement * element,
|
static GstStateChangeReturn gst_adder_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
|
|
||||||
|
static GstBuffer *gst_adder_do_clip (GstCollectPads * pads,
|
||||||
|
GstCollectData * data, GstBuffer * buffer, gpointer user_data);
|
||||||
static GstFlowReturn gst_adder_collected (GstCollectPads * pads,
|
static GstFlowReturn gst_adder_collected (GstCollectPads * pads,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
@ -780,7 +782,7 @@ gst_adder_sink_event (GstPad * pad, GstEvent * event)
|
||||||
case GST_EVENT_FLUSH_STOP:
|
case GST_EVENT_FLUSH_STOP:
|
||||||
/* we received a flush-stop. The collect_event function will push the
|
/* we received a flush-stop. The collect_event function will push the
|
||||||
* event past our element. We simply forward all flush-stop events, even
|
* 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.
|
* 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
|
* We unset the pending flush-stop flag so that we don't send anymore
|
||||||
* flush-stop from the collect function later.
|
* flush-stop from the collect function later.
|
||||||
|
@ -798,7 +800,7 @@ gst_adder_sink_event (GstPad * pad, GstEvent * event)
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_TAG:
|
case GST_EVENT_TAG:
|
||||||
GST_OBJECT_LOCK (adder->collect);
|
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);
|
adder->pending_events = g_list_append (adder->pending_events, event);
|
||||||
GST_OBJECT_UNLOCK (adder->collect);
|
GST_OBJECT_UNLOCK (adder->collect);
|
||||||
goto beach;
|
goto beach;
|
||||||
|
@ -882,6 +884,8 @@ gst_adder_init (GstAdder * adder)
|
||||||
adder->collect = gst_collect_pads_new ();
|
adder->collect = gst_collect_pads_new ();
|
||||||
gst_collect_pads_set_function (adder->collect,
|
gst_collect_pads_set_function (adder->collect,
|
||||||
GST_DEBUG_FUNCPTR (gst_adder_collected), adder);
|
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
|
static void
|
||||||
|
@ -1023,6 +1027,18 @@ gst_adder_release_pad (GstElement * element, GstPad * pad)
|
||||||
gst_element_remove_pad (element, 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
|
static GstFlowReturn
|
||||||
gst_adder_collected (GstCollectPads * pads, gpointer user_data)
|
gst_adder_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
@ -1043,12 +1059,11 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
* mix into a temp (float) buffer and scale afterwards as well
|
* mix into a temp (float) buffer and scale afterwards as well
|
||||||
*/
|
*/
|
||||||
GstAdder *adder;
|
GstAdder *adder;
|
||||||
GSList *collected;
|
GSList *collected, *next = NULL;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
GstBuffer *outbuf = NULL;
|
GstBuffer *outbuf = NULL, *gapbuf = NULL;
|
||||||
gpointer outdata = NULL;
|
gpointer outdata = NULL;
|
||||||
guint outsize;
|
guint outsize;
|
||||||
gboolean empty = TRUE;
|
|
||||||
|
|
||||||
adder = GST_ADDER (user_data);
|
adder = GST_ADDER (user_data);
|
||||||
|
|
||||||
|
@ -1064,20 +1079,26 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
/* get available bytes for reading, this can be 0 which could mean empty
|
/* 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. */
|
* buffers or EOS, which we will catch when we loop over the pads. */
|
||||||
outsize = gst_collect_pads_available (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,
|
GST_LOG_OBJECT (adder,
|
||||||
"starting to cycle through channels, %d bytes available (bps = %d)",
|
"starting to cycle through channels, %d bytes available (bps = %d)",
|
||||||
outsize, adder->bps);
|
outsize, adder->bps);
|
||||||
|
|
||||||
for (collected = pads->data; collected; collected = g_slist_next (collected)) {
|
for (collected = pads->data; collected; collected = next) {
|
||||||
GstCollectData *collect_data;
|
GstCollectData *collect_data;
|
||||||
GstBuffer *inbuf;
|
GstBuffer *inbuf;
|
||||||
guint8 *indata;
|
gboolean is_gap;
|
||||||
guint insize;
|
|
||||||
|
/* take next to see if this is the last collectdata */
|
||||||
|
next = g_slist_next (collected);
|
||||||
|
|
||||||
collect_data = (GstCollectData *) collected->data;
|
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);
|
inbuf = gst_collect_pads_take_buffer (pads, collect_data, outsize);
|
||||||
/* NULL means EOS or an empty buffer so we still need to flush in
|
/* NULL means EOS or an empty buffer so we still need to flush in
|
||||||
* case of an empty buffer. */
|
* case of an empty buffer. */
|
||||||
|
@ -1086,55 +1107,69 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
indata = GST_BUFFER_DATA (inbuf);
|
is_gap = GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP);
|
||||||
insize = GST_BUFFER_SIZE (inbuf);
|
|
||||||
|
|
||||||
|
/* Try to make an output buffer */
|
||||||
if (outbuf == NULL) {
|
if (outbuf == NULL) {
|
||||||
GST_LOG_OBJECT (adder, "channel %p: making output buffer of %d bytes",
|
/* if this is a gap buffer but we have some more pads to check, skip it.
|
||||||
collect_data, outsize);
|
* 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.
|
GST_LOG_OBJECT (adder, "channel %p: preparing output buffer of %d bytes",
|
||||||
* FIXME: we can easily subbuffer and _make_writable.
|
collect_data, outsize);
|
||||||
* FIXME: only create empty buffer for first non-gap buffer, so that we
|
/* make data and metadata writable, can simply return the inbuf when we
|
||||||
* only use adder function when really adding
|
* 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_new_and_alloc (outsize);
|
outbuf = gst_buffer_make_writable (inbuf);
|
||||||
outdata = GST_BUFFER_DATA (outbuf);
|
outdata = GST_BUFFER_DATA (outbuf);
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
|
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 {
|
} 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",
|
GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p",
|
||||||
collect_data, insize, indata);
|
collect_data, insize, indata);
|
||||||
|
|
||||||
/* further buffers, need to add them */
|
/* further buffers, need to add them */
|
||||||
adder->func ((gpointer) outdata, (gpointer) indata, insize);
|
adder->func ((gpointer) outdata, (gpointer) indata, insize);
|
||||||
empty = FALSE;
|
|
||||||
} else {
|
} else {
|
||||||
GST_LOG_OBJECT (adder, "channel %p: skipping %d bytes from data %p",
|
/* skip gap buffer */
|
||||||
collect_data, insize, indata);
|
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) {
|
||||||
if (outbuf == NULL)
|
/* no output buffer, reuse one of the GAP buffers then if we have one */
|
||||||
goto eos;
|
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
|
/* our timestamping is very simple, just an ever incrementing
|
||||||
* counter, the new segment time will take care of their respective
|
* counter, the new segment time will take care of their respective
|
||||||
|
@ -1199,13 +1234,9 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
GST_BUFFER_DURATION (outbuf) = adder->timestamp -
|
GST_BUFFER_DURATION (outbuf) = adder->timestamp -
|
||||||
GST_BUFFER_TIMESTAMP (outbuf);
|
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 */
|
/* send it out */
|
||||||
GST_LOG_OBJECT (adder, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
|
GST_LOG_OBJECT (adder, "pushing outbuf %p, timestamp %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
|
outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
|
||||||
ret = gst_pad_push (adder->srcpad, outbuf);
|
ret = gst_pad_push (adder->srcpad, outbuf);
|
||||||
|
|
||||||
GST_LOG_OBJECT (adder, "pushed outbuf, result = %s", gst_flow_get_name (ret));
|
GST_LOG_OBJECT (adder, "pushed outbuf, result = %s", gst_flow_get_name (ret));
|
||||||
|
|
|
@ -199,6 +199,14 @@ gst_audio_rate_class_init (GstAudioRateClass * klass)
|
||||||
g_param_spec_boolean ("silent", "silent",
|
g_param_spec_boolean ("silent", "silent",
|
||||||
"Don't emit notify for dropped and duplicated frames", DEFAULT_SILENT,
|
"Don't emit notify for dropped and duplicated frames", DEFAULT_SILENT,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
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_object_class_install_property (object_class, ARG_TOLERANCE,
|
||||||
g_param_spec_uint64 ("tolerance", "tolerance",
|
g_param_spec_uint64 ("tolerance", "tolerance",
|
||||||
"Only act if timestamp jitter/imperfection exceeds indicated tolerance (ns)",
|
"Only act if timestamp jitter/imperfection exceeds indicated tolerance (ns)",
|
||||||
|
@ -664,10 +672,10 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
send:
|
||||||
if (GST_BUFFER_SIZE (buf) == 0)
|
if (GST_BUFFER_SIZE (buf) == 0)
|
||||||
goto beach;
|
goto beach;
|
||||||
|
|
||||||
send:
|
|
||||||
/* Now calculate parameters for whichever buffer (either the original
|
/* Now calculate parameters for whichever buffer (either the original
|
||||||
* or truncated one) we're pushing. */
|
* or truncated one) we're pushing. */
|
||||||
GST_BUFFER_OFFSET (buf) = audiorate->next_offset;
|
GST_BUFFER_OFFSET (buf) = audiorate->next_offset;
|
||||||
|
|
|
@ -1469,12 +1469,12 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
|
||||||
"is a demuxer, connecting the pad through multiqueue '%s'",
|
"is a demuxer, connecting the pad through multiqueue '%s'",
|
||||||
GST_OBJECT_NAME (chain->parent->multiqueue));
|
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)))
|
if (!(mqpad = gst_decode_group_control_demuxer_pad (chain->parent, pad)))
|
||||||
goto beach;
|
goto beach;
|
||||||
src = chain->parent->multiqueue;
|
src = chain->parent->multiqueue;
|
||||||
pad = mqpad;
|
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 */
|
/* 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
|
/* Set dpad target to pad again, it might've been unset
|
||||||
* below but we came back here because something failed
|
* 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 */
|
/* take first factory */
|
||||||
factory = g_value_get_object (g_value_array_get_nth (factories, 0));
|
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 */
|
/* 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 */
|
/* 2.1. Try to create an element */
|
||||||
if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
|
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) {
|
if (chain->parent && !chain->elements && src != chain->parent->multiqueue) {
|
||||||
GST_LOG_OBJECT (src, "connecting the pad through 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)))
|
if (!(mqpad = gst_decode_group_control_demuxer_pad (chain->parent, pad)))
|
||||||
goto beach;
|
goto beach;
|
||||||
pad = mqpad;
|
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);
|
gst_decode_pad_activate (dpad, chain);
|
||||||
|
@ -2190,7 +2190,7 @@ gst_decode_chain_free_internal (GstDecodeChain * chain, gboolean hide)
|
||||||
chain->endcaps = NULL;
|
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);
|
||||||
CHAIN_MUTEX_UNLOCK (chain);
|
CHAIN_MUTEX_UNLOCK (chain);
|
||||||
if (!hide) {
|
if (!hide) {
|
||||||
|
@ -2735,8 +2735,8 @@ sort_end_pads (GstDecodePad * da, GstDecodePad * db)
|
||||||
GstStructure *sa, *sb;
|
GstStructure *sa, *sb;
|
||||||
const gchar *namea, *nameb;
|
const gchar *namea, *nameb;
|
||||||
|
|
||||||
capsa = gst_pad_get_caps_reffed (GST_PAD (da));
|
capsa = gst_pad_get_caps_reffed (GST_PAD_CAST (da));
|
||||||
capsb = gst_pad_get_caps_reffed (GST_PAD (db));
|
capsb = gst_pad_get_caps_reffed (GST_PAD_CAST (db));
|
||||||
|
|
||||||
sa = gst_caps_get_structure ((const GstCaps *) capsa, 0);
|
sa = gst_caps_get_structure ((const GstCaps *) capsa, 0);
|
||||||
sb = gst_caps_get_structure ((const GstCaps *) capsb, 0);
|
sb = gst_caps_get_structure ((const GstCaps *) capsb, 0);
|
||||||
|
@ -2989,7 +2989,7 @@ gst_decode_bin_expose (GstDecodeBin * dbin)
|
||||||
|
|
||||||
/* 2. activate and add */
|
/* 2. activate and add */
|
||||||
if (!dpad->exposed
|
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 */
|
/* not really fatal, we can try to add the other pads */
|
||||||
g_warning ("error adding pad to decodebin2");
|
g_warning ("error adding pad to decodebin2");
|
||||||
continue;
|
continue;
|
||||||
|
@ -3167,10 +3167,11 @@ gst_decode_pad_set_blocked (GstDecodePad * dpad, gboolean blocked)
|
||||||
gst_pad_set_blocked_async_full (opad, blocked,
|
gst_pad_set_blocked_async_full (opad, blocked,
|
||||||
(GstPadBlockCallback) source_pad_blocked_cb, gst_object_ref (dpad),
|
(GstPadBlockCallback) source_pad_blocked_cb, gst_object_ref (dpad),
|
||||||
(GDestroyNotify) gst_object_unref);
|
(GDestroyNotify) gst_object_unref);
|
||||||
|
|
||||||
if (blocked) {
|
if (blocked) {
|
||||||
if (dbin->shutdown) {
|
if (dbin->shutdown) {
|
||||||
/* deactivate to force flushing state to prevent NOT_LINKED errors */
|
/* 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 {
|
} else {
|
||||||
gst_object_ref (dpad);
|
gst_object_ref (dpad);
|
||||||
dbin->blocked_pads = g_list_prepend (dbin->blocked_pads, dpad);
|
dbin->blocked_pads = g_list_prepend (dbin->blocked_pads, dpad);
|
||||||
|
@ -3191,7 +3192,7 @@ out:
|
||||||
static void
|
static void
|
||||||
gst_decode_pad_add_drained_check (GstDecodePad * dpad)
|
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);
|
G_CALLBACK (source_pad_event_probe), dpad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3201,7 +3202,7 @@ gst_decode_pad_activate (GstDecodePad * dpad, GstDecodeChain * chain)
|
||||||
g_return_if_fail (chain != NULL);
|
g_return_if_fail (chain != NULL);
|
||||||
|
|
||||||
dpad->chain = chain;
|
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_set_blocked (dpad, TRUE);
|
||||||
gst_decode_pad_add_drained_check (dpad);
|
gst_decode_pad_add_drained_check (dpad);
|
||||||
}
|
}
|
||||||
|
@ -3221,11 +3222,12 @@ gst_decode_pad_new (GstDecodeBin * dbin, GstPad * pad, GstDecodeChain * chain)
|
||||||
{
|
{
|
||||||
GstDecodePad *dpad;
|
GstDecodePad *dpad;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dbin, "making new decodepad");
|
||||||
dpad =
|
dpad =
|
||||||
g_object_new (GST_TYPE_DECODE_PAD, "direction", GST_PAD_DIRECTION (pad),
|
g_object_new (GST_TYPE_DECODE_PAD, "direction", GST_PAD_DIRECTION (pad),
|
||||||
NULL);
|
NULL);
|
||||||
gst_ghost_pad_construct (GST_GHOST_PAD (dpad));
|
gst_ghost_pad_construct (GST_GHOST_PAD_CAST (dpad));
|
||||||
gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), pad);
|
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (dpad), pad);
|
||||||
dpad->chain = chain;
|
dpad->chain = chain;
|
||||||
dpad->dbin = dbin;
|
dpad->dbin = dbin;
|
||||||
|
|
||||||
|
@ -3305,10 +3307,13 @@ unblock_pads (GstDecodeBin * dbin)
|
||||||
{
|
{
|
||||||
GList *tmp;
|
GList *tmp;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (dbin, "unblocking pads");
|
||||||
|
|
||||||
for (tmp = dbin->blocked_pads; tmp; tmp = tmp->next) {
|
for (tmp = dbin->blocked_pads; tmp; tmp = tmp->next) {
|
||||||
GstDecodePad *dpad = (GstDecodePad *) tmp->data;
|
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)
|
if (!opad)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -3317,7 +3322,7 @@ unblock_pads (GstDecodeBin * dbin)
|
||||||
(GstPadBlockCallback) source_pad_blocked_cb, gst_object_ref (dpad),
|
(GstPadBlockCallback) source_pad_blocked_cb, gst_object_ref (dpad),
|
||||||
(GDestroyNotify) gst_object_unref);
|
(GDestroyNotify) gst_object_unref);
|
||||||
/* make flushing, prevent NOT_LINKED */
|
/* 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 (dpad);
|
||||||
gst_object_unref (opad);
|
gst_object_unref (opad);
|
||||||
GST_DEBUG_OBJECT (dpad, "unblocked");
|
GST_DEBUG_OBJECT (dpad, "unblocked");
|
||||||
|
|
|
@ -3182,7 +3182,6 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
|
||||||
else
|
else
|
||||||
g_object_set (uridecodebin, "download", FALSE, NULL);
|
g_object_set (uridecodebin, "download", FALSE, NULL);
|
||||||
|
|
||||||
|
|
||||||
/* configure subtitle encoding */
|
/* configure subtitle encoding */
|
||||||
g_object_set (uridecodebin, "subtitle-encoding", playbin->encoding, NULL);
|
g_object_set (uridecodebin, "subtitle-encoding", playbin->encoding, NULL);
|
||||||
/* configure uri */
|
/* configure uri */
|
||||||
|
@ -3368,6 +3367,17 @@ deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (select->selector) {
|
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_element_set_state (select->selector, GST_STATE_NULL);
|
||||||
gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
|
gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
|
||||||
select->selector = NULL;
|
select->selector = NULL;
|
||||||
|
|
|
@ -86,6 +86,7 @@ struct _GstURIDecodeBin
|
||||||
gboolean use_buffering;
|
gboolean use_buffering;
|
||||||
|
|
||||||
GstElement *source;
|
GstElement *source;
|
||||||
|
GstElement *queue;
|
||||||
GstElement *typefind;
|
GstElement *typefind;
|
||||||
guint have_type_id; /* have-type signal id from typefind */
|
guint have_type_id; /* have-type signal id from typefind */
|
||||||
GSList *decodebins;
|
GSList *decodebins;
|
||||||
|
@ -1076,7 +1077,7 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw,
|
||||||
GstPad *sinkpad;
|
GstPad *sinkpad;
|
||||||
|
|
||||||
/* insert a queue element right before the raw pad */
|
/* 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);
|
gst_bin_add (GST_BIN_CAST (decoder), outelem);
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (outelem, "sink");
|
sinkpad = gst_element_get_static_pad (outelem, "sink");
|
||||||
|
@ -1084,6 +1085,9 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw,
|
||||||
gst_object_unref (sinkpad);
|
gst_object_unref (sinkpad);
|
||||||
gst_object_unref (pad);
|
gst_object_unref (pad);
|
||||||
|
|
||||||
|
/* save queue pointer so we can remove it later */
|
||||||
|
decoder->queue = outelem;
|
||||||
|
|
||||||
/* get the new raw srcpad */
|
/* get the new raw srcpad */
|
||||||
pad = gst_element_get_static_pad (outelem, "src");
|
pad = gst_element_get_static_pad (outelem, "src");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1482,10 +1486,12 @@ could_not_link:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (decoder, CORE, NEGOTIATION,
|
GST_ELEMENT_ERROR (decoder, CORE, NEGOTIATION,
|
||||||
(NULL), ("Can't link source to typefind element"));
|
(NULL), ("Can't link source to typefind element"));
|
||||||
|
gst_bin_remove (GST_BIN_CAST (decoder), typefind);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove source and all related elements */
|
||||||
static void
|
static void
|
||||||
remove_source (GstURIDecodeBin * bin)
|
remove_source (GstURIDecodeBin * bin)
|
||||||
{
|
{
|
||||||
|
@ -1506,6 +1512,18 @@ remove_source (GstURIDecodeBin * bin)
|
||||||
}
|
}
|
||||||
bin->source = NULL;
|
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. */
|
/* is called when a dynamic source element created a new pad. */
|
||||||
|
|
|
@ -732,6 +732,116 @@ GST_START_TEST (test_remove_pad)
|
||||||
GST_END_TEST;
|
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 *
|
static Suite *
|
||||||
adder_suite (void)
|
adder_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -745,6 +855,7 @@ adder_suite (void)
|
||||||
tcase_add_test (tc_chain, test_live_seeking);
|
tcase_add_test (tc_chain, test_live_seeking);
|
||||||
tcase_add_test (tc_chain, test_add_pad);
|
tcase_add_test (tc_chain, test_add_pad);
|
||||||
tcase_add_test (tc_chain, test_remove_pad);
|
tcase_add_test (tc_chain, test_remove_pad);
|
||||||
|
tcase_add_test (tc_chain, test_clip);
|
||||||
|
|
||||||
/* Use a longer timeout */
|
/* Use a longer timeout */
|
||||||
#ifdef HAVE_VALGRIND
|
#ifdef HAVE_VALGRIND
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* 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);
|
GST_DEBUG_CATEGORY (appsrc_playbin_debug);
|
||||||
#define GST_CAT_DEFAULT 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);
|
gst_element_set_state (app->playbin, GST_STATE_NULL);
|
||||||
|
|
||||||
/* free the file */
|
/* free the file */
|
||||||
g_mapped_file_free (app->file);
|
g_mapped_file_unref (app->file);
|
||||||
|
|
||||||
gst_object_unref (bus);
|
gst_object_unref (bus);
|
||||||
g_main_loop_unref (app->loop);
|
g_main_loop_unref (app->loop);
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* 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);
|
GST_DEBUG_CATEGORY (appsrc_playbin_debug);
|
||||||
#define GST_CAT_DEFAULT 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);
|
gst_element_set_state (app->playbin, GST_STATE_NULL);
|
||||||
|
|
||||||
/* free the file */
|
/* free the file */
|
||||||
g_mapped_file_free (app->file);
|
g_mapped_file_unref (app->file);
|
||||||
|
|
||||||
gst_object_unref (bus);
|
gst_object_unref (bus);
|
||||||
g_main_loop_unref (app->loop);
|
g_main_loop_unref (app->loop);
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* 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);
|
GST_DEBUG_CATEGORY (appsrc_playbin_debug);
|
||||||
#define GST_CAT_DEFAULT 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);
|
gst_element_set_state (app->playbin, GST_STATE_NULL);
|
||||||
|
|
||||||
/* free the file */
|
/* free the file */
|
||||||
g_mapped_file_free (app->file);
|
g_mapped_file_unref (app->file);
|
||||||
|
|
||||||
gst_object_unref (bus);
|
gst_object_unref (bus);
|
||||||
g_main_loop_unref (app->loop);
|
g_main_loop_unref (app->loop);
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* 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);
|
GST_DEBUG_CATEGORY (appsrc_playbin_debug);
|
||||||
#define GST_CAT_DEFAULT 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);
|
gst_element_set_state (app->playbin, GST_STATE_NULL);
|
||||||
|
|
||||||
/* free the file */
|
/* free the file */
|
||||||
g_mapped_file_free (app->file);
|
g_mapped_file_unref (app->file);
|
||||||
|
|
||||||
gst_object_unref (bus);
|
gst_object_unref (bus);
|
||||||
g_main_loop_unref (app->loop);
|
g_main_loop_unref (app->loop);
|
||||||
|
|
|
@ -2391,8 +2391,13 @@ msg_clock_lost (GstBus * bus, GstMessage * message, GstPipeline * data)
|
||||||
|
|
||||||
#ifdef HAVE_X
|
#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
|
static GstBusSyncReply
|
||||||
bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data)
|
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")) {
|
gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
|
||||||
GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message));
|
GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message));
|
||||||
|
|
||||||
g_print ("got prepare-xwindow-id\n");
|
g_print ("got prepare-xwindow-id, setting XID %lu\n", embed_xid);
|
||||||
if (!embed_xid) {
|
|
||||||
embed_xid = GDK_WINDOW_XID (GDK_WINDOW (video_window->window));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_object_class_find_property (G_OBJECT_GET_CLASS (element),
|
if (g_object_class_find_property (G_OBJECT_GET_CLASS (element),
|
||||||
"force-aspect-ratio")) {
|
"force-aspect-ratio")) {
|
||||||
g_object_set (element, "force-aspect-ratio", TRUE, NULL);
|
g_object_set (element, "force-aspect-ratio", TRUE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)),
|
/* Should have been initialised from main thread before (can't use
|
||||||
embed_xid);
|
* 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;
|
return GST_BUS_PASS;
|
||||||
}
|
}
|
||||||
|
@ -2427,6 +2435,21 @@ handle_expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
g_print ("Window realize: video window XID = %lu\n", embed_xid);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
msg_eos (GstBus * bus, GstMessage * message, GstPipeline * data)
|
msg_eos (GstBus * bus, GstMessage * message, GstPipeline * data)
|
||||||
|
@ -2623,9 +2646,11 @@ main (int argc, char **argv)
|
||||||
/* initialize gui elements ... */
|
/* initialize gui elements ... */
|
||||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||||
video_window = gtk_drawing_area_new ();
|
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_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_widget_set_double_buffered (video_window, FALSE);
|
||||||
|
|
||||||
statusbar = gtk_statusbar_new ();
|
statusbar = gtk_statusbar_new ();
|
||||||
status_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), "seek");
|
status_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), "seek");
|
||||||
gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stopped");
|
gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stopped");
|
||||||
|
@ -2891,6 +2916,14 @@ main (int argc, char **argv)
|
||||||
/* show the gui. */
|
/* show the gui. */
|
||||||
gtk_widget_show_all (window);
|
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) {
|
if (verbose) {
|
||||||
g_signal_connect (pipeline, "deep_notify",
|
g_signal_connect (pipeline, "deep_notify",
|
||||||
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
||||||
|
|
|
@ -146,7 +146,7 @@ create_window (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
|
||||||
GstXOverlay *ov = NULL;
|
GstXOverlay *ov = NULL;
|
||||||
|
|
||||||
s = gst_message_get_structure (message);
|
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;
|
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 (100, (GSourceFunc) cycle_window, ov);
|
||||||
g_timeout_add (2000, (GSourceFunc) toggle_events, ov);
|
g_timeout_add (2000, (GSourceFunc) toggle_events, ov);
|
||||||
|
|
||||||
|
gst_message_unref (message);
|
||||||
return GST_BUS_DROP;
|
return GST_BUS_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,32 +38,9 @@
|
||||||
|
|
||||||
static GtkWidget *video_window = NULL;
|
static GtkWidget *video_window = NULL;
|
||||||
static GstElement *sink = NULL;
|
static GstElement *sink = NULL;
|
||||||
static guint embed_xid = 0;
|
static gulong embed_xid = 0;
|
||||||
static GdkGC *trans_gc = NULL;
|
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
|
static void
|
||||||
redraw_overlay (GtkWidget * widget)
|
redraw_overlay (GtkWidget * widget)
|
||||||
{
|
{
|
||||||
|
@ -101,6 +78,20 @@ handle_expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
|
msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
|
||||||
{
|
{
|
||||||
|
@ -192,13 +183,16 @@ main (int argc, char **argv)
|
||||||
gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
|
gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
|
||||||
gst_element_link (src, sink);
|
gst_element_link (src, sink);
|
||||||
|
|
||||||
g_object_set (G_OBJECT (sink), "autopaint-colorkey", FALSE, "force-aspect-ratio", TRUE, "draw-borders", FALSE, "colorkey", 0x7F7F7F, /* gray */
|
#define COLOR_GRAY 0x7F7F7F
|
||||||
NULL);
|
|
||||||
|
g_object_set (G_OBJECT (sink), "autopaint-colorkey", FALSE,
|
||||||
|
"force-aspect-ratio", TRUE, "draw-borders", FALSE,
|
||||||
|
"colorkey", COLOR_GRAY, NULL);
|
||||||
|
|
||||||
/* check xvimagesink capabilities */
|
/* check xvimagesink capabilities */
|
||||||
sret = gst_element_set_state (pipeline, GST_STATE_READY);
|
sret = gst_element_set_state (pipeline, GST_STATE_READY);
|
||||||
if (sret == GST_STATE_CHANGE_FAILURE) {
|
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);
|
gst_object_unref (pipeline);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -223,8 +217,6 @@ main (int argc, char **argv)
|
||||||
g_value_array_free (arr);
|
g_value_array_free (arr);
|
||||||
|
|
||||||
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
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);
|
gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
|
||||||
g_signal_connect (bus, "message::state-changed",
|
g_signal_connect (bus, "message::state-changed",
|
||||||
G_CALLBACK (msg_state_changed), pipeline);
|
G_CALLBACK (msg_state_changed), pipeline);
|
||||||
|
@ -242,12 +234,28 @@ main (int argc, char **argv)
|
||||||
G_CALLBACK (handle_resize_cb), NULL);
|
G_CALLBACK (handle_resize_cb), NULL);
|
||||||
g_signal_connect (G_OBJECT (video_window), "expose-event",
|
g_signal_connect (G_OBJECT (video_window), "expose-event",
|
||||||
G_CALLBACK (handle_expose_cb), NULL);
|
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_widget_set_double_buffered (video_window, FALSE);
|
||||||
gtk_container_add (GTK_CONTAINER (window), video_window);
|
gtk_container_add (GTK_CONTAINER (window), video_window);
|
||||||
|
|
||||||
/* show the gui and play */
|
/* show the gui and play */
|
||||||
|
|
||||||
gtk_widget_show_all (window);
|
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);
|
g_idle_add (start_pipeline, pipeline);
|
||||||
gtk_main ();
|
gtk_main ();
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,8 @@ EXPORTS
|
||||||
gst_rtcp_packet_set_rb
|
gst_rtcp_packet_set_rb
|
||||||
gst_rtcp_packet_sr_get_sender_info
|
gst_rtcp_packet_sr_get_sender_info
|
||||||
gst_rtcp_packet_sr_set_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_rtcp_unix_to_ntp
|
||||||
gst_rtp_buffer_allocate_data
|
gst_rtp_buffer_allocate_data
|
||||||
gst_rtp_buffer_calc_header_len
|
gst_rtp_buffer_calc_header_len
|
||||||
|
|
Loading…
Reference in a new issue