gobject_class->get_property = gst_alsasrc_get_property;
gobject_class->set_property = gst_alsasrc_set_property;
+ gst_element_class_set_details_simple (gstelement_class,
+ "Audio source (ALSA)", "Source/Audio",
+ "Read from a sound card via ALSA", "Wim Taymans <wim@fluendo.com>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&alsasrc_src_factory));
+
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_alsasrc_change_state);
+
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasrc_getcaps);
+ gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_alsasrc_create);
gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_alsasrc_open);
gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasrc_prepare);
}
}
+ static GstStateChangeReturn
+ gst_alsasrc_change_state (GstElement * element, GstStateChange transition)
+ {
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (element);
+ GstAlsaSrc *asrc = GST_ALSA_SRC (element);
+ GstClock *clk;
+
+ switch (transition) {
+ /* Show the compiler that we care */
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ clk = src->clock;
+ asrc->driver_timestamps = FALSE;
+ if (GST_IS_SYSTEM_CLOCK (clk)) {
+ gint clocktype;
+ g_object_get (clk, "clock-type", &clocktype, NULL);
+ if (clocktype == GST_CLOCK_TYPE_MONOTONIC) {
+ asrc->driver_timestamps = TRUE;
+ }
+ }
+ break;
+ }
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ return ret;
+ }
+
+ static GstFlowReturn
+ gst_alsasrc_create (GstBaseSrc * bsrc, guint64 offset, guint length,
+ GstBuffer ** outbuf)
+ {
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstAlsaSrc *asrc = GST_ALSA_SRC (bsrc);
+
+ ret =
+ GST_BASE_SRC_CLASS (parent_class)->create (bsrc, offset, length, outbuf);
+ if (asrc->driver_timestamps == TRUE && *outbuf) {
+ GST_BUFFER_TIMESTAMP (*outbuf) =
+ gst_alsasrc_get_timestamp ((GstAlsaSrc *) bsrc);
+ }
+
+ return ret;
+ }
+
static void
-gst_alsasrc_init (GstAlsaSrc * alsasrc, GstAlsaSrcClass * g_class)
+gst_alsasrc_init (GstAlsaSrc * alsasrc)
{
GST_DEBUG_OBJECT (alsasrc, "initializing");
guint64 in_offset;
GstClockTime time, stop, render_start, render_stop, sample_offset;
GstClockTimeDiff sync_offset, ts_offset;
+ GstBaseAudioSinkClass *bclass;
GstBaseAudioSink *sink;
GstRingBuffer *ringbuf;
- gint64 diff, align, ctime, cstop;
+ gint64 diff, align;
+ guint64 ctime, cstop;
+ gsize offset;
guint8 *data;
- guint size;
+ gsize size;
guint samples, written;
gint bps;
gint accum;
GST_OBJECT_UNLOCK (sink);
}
+ /* Before we go on, let's see if we need to payload the data. If yes, we also
+ * need to unref the output buffer before leaving. */
+ if (bclass->payload) {
+ out = bclass->payload (sink, buf);
+
+ if (!out)
+ goto payload_failed;
+
+ buf = out;
+ }
+
bps = ringbuf->spec.bytes_per_sample;
- size = GST_BUFFER_SIZE (buf);
+ size = gst_buffer_get_size (buf);
if (G_UNLIKELY (size % bps) != 0)
goto wrong_size;
{
GST_DEBUG_OBJECT (sink, "preroll got interrupted: %d (%s)", ret,
gst_flow_get_name (ret));
- return ret;
+ gst_buffer_unmap (buf, data, size);
+ goto done;
}
sync_latency_failed:
{
XmpTag *last_xmp_tag = NULL;
GSList *pending_tags = NULL;
+ /* Used for strucuture xmp tags */
+ XmpTag *context_tag = NULL;
+
GstXmpNamespaceMap ns_map[] = {
-- {"dc", NULL},
-- {"exif", NULL},
-- {"tiff", NULL},
-- {"xap", NULL},
-- {"photoshop", NULL},
-- {"Iptc4xmpCore", NULL},
- {"Iptc4xmpExt", NULL},
++ {"dc", NULL}
++ ,
++ {"exif", NULL}
++ ,
++ {"tiff", NULL}
++ ,
++ {"xap", NULL}
++ ,
++ {"photoshop", NULL}
++ ,
++ {"Iptc4xmpCore", NULL}
++ ,
++ {"Iptc4xmpExt", NULL}
++ ,
{NULL, NULL}
};
xmp_tags_initialize ();
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
- g_return_val_if_fail (GST_BUFFER_SIZE (buffer) > 0, NULL);
- xps = (const gchar *) GST_BUFFER_DATA (buffer);
- len = GST_BUFFER_SIZE (buffer);
+ GST_LOG ("Starting xmp parsing");
+
+ xps = gst_buffer_map (buffer, &len, NULL, GST_MAP_READ);
+ g_return_val_if_fail (len > 0, NULL);
+
xpe = &xps[len + 1];
/* check header and footer */
self->fps_n = self->fps_d = 0;
}
- ret = self->video_sink_event (pad, gst_event_ref (event));
+ ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
- if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, position;
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
- GST_DEBUG_OBJECT (pad, "Newsegment event: %" GST_PTR_FORMAT,
- event->structure);
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
+ GST_DEBUG_OBJECT (pad, "segment event: %" GST_PTR_FORMAT, event);
+ gst_event_parse_segment (event, &self->video_segment);
- if (format != GST_FORMAT_TIME) {
+ if (self->video_segment.format != GST_FORMAT_TIME) {
GST_ERROR_OBJECT (pad, "Newsegment event in non-time format: %s",
- gst_format_get_name (format));
+ gst_format_get_name (self->video_segment.format));
gst_object_unref (event);
gst_object_unref (self);
return FALSE;
break;
}
- ret = self->subtitle_sink_event (pad, gst_event_ref (event));
+ ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
- if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gboolean update;
- gdouble rate, applied_rate;
- gint64 start, stop, position;
-
- GST_DEBUG_OBJECT (pad, "Newsegment event: %" GST_PTR_FORMAT,
- event->structure);
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
-
- GST_DEBUG_OBJECT (pad, "Old subtitle segment: %" GST_SEGMENT_FORMAT,
- &self->subtitle_segment);
- if (self->subtitle_segment.format != format) {
- GST_DEBUG_OBJECT (pad, "Subtitle segment format changed: %s -> %s",
- gst_format_get_name (self->subtitle_segment.format),
- gst_format_get_name (format));
- gst_segment_init (&self->subtitle_segment, format);
- }
-
- gst_segment_set_newsegment_full (&self->subtitle_segment, update, rate,
- applied_rate, format, start, stop, position);
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
+ GST_DEBUG_OBJECT (pad, "segment event: %" GST_PTR_FORMAT, event);
+ gst_event_parse_segment (event, &self->subtitle_segment);
GST_DEBUG_OBJECT (pad, "New subtitle segment: %" GST_SEGMENT_FORMAT,
&self->subtitle_segment);
}
}
static void
-gst_subtitle_overlay_init (GstSubtitleOverlay * self,
- GstSubtitleOverlayClass * klass)
+gst_subtitle_overlay_init (GstSubtitleOverlay * self)
{
GstPadTemplate *templ;
- GstIterator *it;
- GValue item = { 0, };
GstPad *proxypad = NULL;
self->lock = g_mutex_new ();
gst_pad_set_chain_function (self->video_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_chain));
- proxypad = NULL;
- it = gst_pad_iterate_internal_links (self->video_sinkpad);
- if (G_UNLIKELY (!it
- || gst_iterator_next (it, &item) != GST_ITERATOR_OK
- || ((proxypad = g_value_dup_object (&item)) == NULL))) {
- GST_ERROR_OBJECT (self,
- "Failed to get internally linked pad from video sinkpad");
- }
- if (it)
- gst_iterator_free (it);
+ proxypad =
+ GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
+ (self->video_sinkpad)));
self->video_block_pad = proxypad;
- g_value_unset (&item);
++
gst_element_add_pad (GST_ELEMENT_CAST (self), self->video_sinkpad);
templ = gst_static_pad_template_get (&subtitle_sinktemplate);
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_getcaps));
gst_pad_set_acceptcaps_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_acceptcaps));
- gst_pad_set_bufferalloc_function (self->subtitle_sinkpad, NULL);
- proxypad = NULL;
- it = gst_pad_iterate_internal_links (self->subtitle_sinkpad);
- if (G_UNLIKELY (!it
- || gst_iterator_next (it, &item) != GST_ITERATOR_OK
- || ((proxypad = g_value_dup_object (&item)) == NULL))) {
- GST_ERROR_OBJECT (self,
- "Failed to get internally linked pad from subtitle sinkpad");
- }
- if (it)
- gst_iterator_free (it);
- g_value_unset (&item);
+ proxypad =
+ GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
+ (self->subtitle_sinkpad)));
self->subtitle_block_pad = proxypad;
gst_element_add_pad (GST_ELEMENT_CAST (self), self->subtitle_sinkpad);
"Don't produce buffers before the first one we receive",
DEFAULT_SKIP_TO_FIRST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (element_class,
+ "Video rate adjuster", "Filter/Effect/Video",
+ "Drops/duplicates/adjusts timestamps on video frames to make a perfect stream",
+ "Wim Taymans <wim@fluendo.com>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_video_rate_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_video_rate_src_template));
+
+ /**
+ * GstVideoRate:drop-only:
+ *
+ * Only drop frames, no duplicates are produced.
+ *
+ * Since: 0.10.34
+ */
+ g_object_class_install_property (object_class, ARG_DROP_ONLY,
+ g_param_spec_boolean ("drop-only", "Only Drop",
+ "Only drop frames, no duplicates are produced",
+ DEFAULT_DROP_ONLY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstVideoRate:average-period:
+ *
+ * Arrange for maximum framerate by dropping frames beyond a certain framerate,
+ * where the framerate is calculated using a moving average over the
+ * configured.
+ *
+ * Since: 0.10.34
+ */
+ g_object_class_install_property (object_class, ARG_AVERAGE_PERIOD,
+ g_param_spec_uint64 ("average-period", "Period over which to average",
+ "Period over which to average the framerate (in ns) (0 = disabled)",
+ 0, G_MAXINT64, DEFAULT_AVERAGE_PERIOD,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
element_class->change_state = GST_DEBUG_FUNCPTR (gst_video_rate_change_state);
}
GST_BUFFER_DURATION (outbuf) = videorate->next_ts - push_ts;
}
- /* adapt for looping, bring back to time in current segment. */
- GST_BUFFER_TIMESTAMP (outbuf) = push_ts - videorate->segment.base;
+ /* We do not need to update time in VFR (variable frame rate) mode */
+ if (!videorate->drop_only) {
+ /* adapt for looping, bring back to time in current segment. */
+ GST_BUFFER_TIMESTAMP (outbuf) = push_ts - videorate->segment.accum;
+ }
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (videorate->srcpad));
GST_LOG_OBJECT (videorate,
"old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT,