Merge branch 'master' into 0.11
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 6 Sep 2011 13:24:32 +0000 (15:24 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 6 Sep 2011 13:24:32 +0000 (15:24 +0200)
Conflicts:
gst-libs/gst/audio/audio.h
gst-libs/gst/audio/gstaudiodecoder.c
gst-libs/gst/audio/gstaudiodecoder.h
gst-libs/gst/audio/gstaudioencoder.c
gst-libs/gst/audio/gstbaseaudioencoder.h
gst/playback/Makefile.am
gst/playback/gstplaybin.c
gst/playback/gstplaysink.c
gst/playback/gstplaysinkvideoconvert.c
gst/playback/gstsubtitleoverlay.c
gst/videorate/gstvideorate.c
gst/videoscale/gstvideoscale.c
win32/common/libgstaudio.def

45 files changed:
1  2 
docs/libs/Makefile.am
docs/libs/gst-plugins-base-libs-docs.sgml
docs/libs/gst-plugins-base-libs-sections.txt
docs/libs/gst-plugins-base-libs.types
gst-libs/gst/audio/Makefile.am
gst-libs/gst/audio/audio.h
gst-libs/gst/audio/gstaudiodecoder.c
gst-libs/gst/audio/gstaudiodecoder.h
gst-libs/gst/audio/gstaudioencoder.c
gst-libs/gst/audio/gstaudioencoder.h
gst-libs/gst/audio/gstaudiofilterexample.c
gst-libs/gst/audio/gstaudioprocess.c
gst-libs/gst/audio/gstaudioprocess.h
gst-libs/gst/audio/gstaudioringbuffer.c
gst-libs/gst/audio/gstaudioringbuffer.h
gst-libs/gst/audio/gstbaseaudiosrc.c.orig
gst-libs/gst/audio/gstbaseaudiosrc.c.rej
gst-libs/gst/audio/gstringbufferthread.c
gst-libs/gst/audio/gstringbufferthread.h
gst-libs/gst/cdda/gst-plugins-base-sha1-2.patch
gst-libs/gst/cdda/gstcddabasesrc.c.orig
gst-libs/gst/rtp/gst-plugins-base-rtcp-feedback.patch
gst-libs/gst/rtp/gstbasertppayload.c.orig
gst-libs/gst/rtp/gstbasertppayload.c.rej
gst-libs/gst/rtp/gstrtpbuffer.c.new
gst-libs/gst/rtsp/gstrtspconnection.c.orig
gst-libs/gst/rtsp/rtsp-marshal.c
gst-libs/gst/rtsp/rtsp-marshal.h
gst-libs/gst/rtsp/rtspdefs.patch
gst-libs/gst/video/gstmetavideoclip.h
gst/encoding/gstencodebin.c
gst/playback/Makefile.am
gst/playback/gstdecodebin2.c
gst/playback/gstplaysink.c
gst/playback/gstplaysinkvideoconvert.c
gst/playback/gstsubtitleoverlay.c
gst/videorate/gstvideorate.c
gst/videorate/videorate-discont.patch
gst/videoscale/gstvideoscale.c
gst/videoscale/gstvideoscale.h
tests/check/libs/profile.c
tests/check/libs/tag.c
tests/check/libs/video.c
tests/examples/seek/seek.c
win32/common/libgstaudio.def

diff --combined docs/libs/Makefile.am
@@@ -79,7 -79,13 +79,13 @@@ SCANOBJ_DEPS = 
        $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la
  
  # Header files to ignore when scanning.
- IGNORE_HFILES = pbutils-private.h
+ IGNORE_HFILES = pbutils-private.h gsttageditingprivate.h id3v2.h \
+       kiss_fft_f32.h kiss_fft_f64.h kiss_fftr_f32.h kiss_fftr_f64.h \
+       kiss_fftr_s16.h kiss_fftr_s32.h kiss_fft_s16.h kiss_fft_s32.h \
+       _kiss_fft_guts_f32.h _kiss_fft_guts_f64.h _kiss_fft_guts_s16.h \
+       _kiss_fft_guts_s16.h _kiss_fft_guts_s32.h _kiss_fft_guts_s32.h \
+       interfaces-marshal.h pbutils-marshal.h
  
  # Images to copy into HTML directory.
  HTML_IMAGES =
@@@ -92,7 -98,7 +98,7 @@@ extra_files 
  
  # CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib
  # contains GtkObjects/GObjects and you want to document signals and properties.
 -GTKDOC_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS)
 +GTKDOC_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) -DGST_USE_UNSTABLE_API
  GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_BASE_LIBS)
  
  GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC)
@@@ -44,6 -44,8 +44,8 @@@
        </para>
        <xi:include href="xml/gstaudio.xml" />
        <xi:include href="xml/gstaudioclock.xml" />
+       <xi:include href="xml/gstaudiodecoder.xml" />
+       <xi:include href="xml/gstaudioencoder.xml" />
        <xi:include href="xml/gstaudiofilter.xml" />
        <xi:include href="xml/gstaudiomixerutils.xml" />
        <xi:include href="xml/gstaudiosink.xml" />
        <xi:include href="xml/gsttunerchannel.xml" />
        <xi:include href="xml/gsttunernorm.xml" />
        <xi:include href="xml/gstvideoorientation.xml" />
 -      <xi:include href="xml/gstxoverlay.xml" />
 +      <xi:include href="xml/gstvideooverlay.xml" />
      </chapter>
  
      <chapter id="gstreamer-netbuffer">
@@@ -35,6 -35,7 +35,7 @@@ GST_IS_APP_BUFFE
  GST_IS_APP_BUFFER_CLASS
  GST_TYPE_APP_BUFFER
  GST_TYPE_APP_STREAM_TYPE
+ gst_app_stream_type_get_type
  <SUBSECTION Private>
  GstAppSrc
  GstAppSrcPrivate
@@@ -125,6 -126,86 +126,86 @@@ GST_AUDIO_CLOCK_CAS
  </SECTION>
  
  <SECTION>
+ <FILE>gstaudiodecoder</FILE>
+ <INCLUDE>gst/audio/gstaudiodecoder.h</INCLUDE>
+ GstAudioDecoder
+ GstAudioDecoderClass
+ GST_AUDIO_DECODER_ERROR
+ GST_AUDIO_DECODER_SINK_NAME
+ GST_AUDIO_DECODER_SINK_PAD
+ GST_AUDIO_DECODER_SRC_NAME
+ GST_AUDIO_DECODER_SRC_PAD
+ gst_audio_decoder_finish_frame
+ gst_audio_decoder_get_audio_info
+ gst_audio_decoder_get_byte_time
+ gst_audio_decoder_get_delay
+ gst_audio_decoder_get_latency
+ gst_audio_decoder_get_max_errors
+ gst_audio_decoder_get_min_latency
+ gst_audio_decoder_get_parse_state
+ gst_audio_decoder_get_plc
+ gst_audio_decoder_get_plc_aware
+ gst_audio_decoder_get_tolerance
+ gst_audio_decoder_set_byte_time
+ gst_audio_decoder_set_latency
+ gst_audio_decoder_set_max_errors
+ gst_audio_decoder_set_min_latency
+ gst_audio_decoder_set_plc
+ gst_audio_decoder_set_plc_aware
+ gst_audio_decoder_set_tolerance
+ <SUBSECTION Standard>
+ GST_AUDIO_DECODER
+ GST_IS_AUDIO_DECODER
+ GST_TYPE_AUDIO_DECODER
+ gst_audio_decoder_get_type
+ GST_AUDIO_DECODER_CLASS
+ GST_IS_AUDIO_DECODER_CLASS
+ GST_AUDIO_DECODER_GET_CLASS
+ GstAudioDecoderPrivate
+ </SECTION>
+ <SECTION>
+ <FILE>gstaudioencoder</FILE>
+ <INCLUDE>gst/audio/gstaudioencoder.h</INCLUDE>
+ GstAudioEncoder
+ GstAudioEncoderClass
+ GST_AUDIO_ENCODER_SEGMENT
+ GST_AUDIO_ENCODER_SINK_NAME
+ GST_AUDIO_ENCODER_SINK_PAD
+ GST_AUDIO_ENCODER_SRC_NAME
+ GST_AUDIO_ENCODER_SRC_PAD
+ gst_audio_encoder_finish_frame
+ gst_audio_encoder_get_audio_info
+ gst_audio_encoder_get_frame_max
+ gst_audio_encoder_get_frame_samples
+ gst_audio_encoder_get_hard_resync
+ gst_audio_encoder_get_latency
+ gst_audio_encoder_get_lookahead
+ gst_audio_encoder_get_mark_granule
+ gst_audio_encoder_get_perfect_timestamp
+ gst_audio_encoder_get_tolerance
+ gst_audio_encoder_proxy_getcaps
+ gst_audio_encoder_set_frame_max
+ gst_audio_encoder_set_frame_samples
+ gst_audio_encoder_set_hard_resync
+ gst_audio_encoder_set_latency
+ gst_audio_encoder_set_lookahead
+ gst_audio_encoder_set_mark_granule
+ gst_audio_encoder_set_perfect_timestamp
+ gst_audio_encoder_set_tolerance
+ <SUBSECTION Standard>
+ GST_AUDIO_ENCODER
+ GST_AUDIO_ENCODER_CAST
+ GST_IS_AUDIO_ENCODER
+ GST_TYPE_AUDIO_ENCODER
+ gst_audio_encoder_get_type
+ GST_AUDIO_ENCODER_CLASS
+ GST_IS_AUDIO_ENCODER_CLASS
+ GST_AUDIO_ENCODER_GET_CLASS
+ GstAudioEncoderPrivate
+ </SECTION>
+ <SECTION>
  <FILE>gstaudiofilter</FILE>
  <INCLUDE>gst/audio/gstaudiofilter.h</INCLUDE>
  GstAudioFilter
@@@ -465,6 -546,8 +546,8 @@@ KISS_FFT_F64_SI
  <INCLUDE>gst/floatcast/floatcast.h</INCLUDE>
  gst_cast_double
  gst_cast_float
+ <SUBSECTION Standard>
+ inline
  </SECTION>
  
  
@@@ -795,22 -878,26 +878,22 @@@ gst_video_orientation_get_typ
  </SECTION>
  
  <SECTION>
 -<FILE>gstxoverlay</FILE>
 -<INCLUDE>gst/interfaces/xoverlay.h</INCLUDE>
 +<FILE>gstvideooverlay</FILE>
 +<INCLUDE>gst/interfaces/videooverlay.h</INCLUDE>
  GstXOverlay
 -GstXOverlayClass
 -gst_x_overlay_set_xwindow_id
 -gst_x_overlay_got_xwindow_id
 -gst_x_overlay_got_window_handle
 -gst_x_overlay_set_window_handle
 -gst_x_overlay_prepare_xwindow_id
 -gst_x_overlay_expose
 -gst_x_overlay_handle_events
 -gst_x_overlay_set_render_rectangle
 -<SUBSECTION Standard>
 -GST_TYPE_X_OVERLAY
 -GST_X_OVERLAY
 -GST_X_OVERLAY_CLASS
 -GST_X_OVERLAY_GET_CLASS
 -GST_IS_X_OVERLAY
 -GST_IS_X_OVERLAY_CLASS
 -gst_x_overlay_get_type
 +GstXOverlayIface
 +gst_video_overlay_got_window_handle
 +gst_video_overlay_set_window_handle
 +gst_video_overlay_prepare_window_handle
 +gst_video_overlay_expose
 +gst_video_overlay_handle_events
 +gst_video_overlay_set_render_rectangle
 +<SUBSECTION Standard>
 +GST_TYPE_VIDEO_OVERLAY
 +GST_VIDEO_OVERLAY
 +GST_IS_VIDEO_OVERLAY
 +GST_VIDEO_OVERLAY_GET_IFACE
 +gst_video_overlay_get_type
  </SECTION>
  
  
@@@ -1832,7 -1919,7 +1915,7 @@@ GST_IS_TAG_MUX_CLAS
  GST_TAG_MUX
  GST_TAG_MUX_CLASS
  GST_TYPE_TAG_MUX
- gst_tag_demux_get_type
+ gst_tag_mux_get_type
  </SECTION>
  
  <SECTION>
@@@ -1849,6 -1936,7 +1932,7 @@@ gst_tag_get_language_code_iso_639_2
  <SECTION>
  <FILE>gsttaglicenses</FILE>
  <INCLUDE>gst/tag/tag.h</INCLUDE>
+ GstTagLicenseFlags
  gst_tag_get_license_flags
  gst_tag_get_license_nick
  gst_tag_get_license_title
@@@ -2138,6 -2226,7 +2222,7 @@@ GST_VIDEO_SIZE_RANG
  GST_VIDEO_BUFFER_TFF
  GST_VIDEO_BUFFER_RFF
  GST_VIDEO_BUFFER_ONEFIELD
+ GST_VIDEO_BUFFER_PROGRESSIVE
  GstVideoFormat
  gst_video_calculate_display_ratio
  gst_video_frame_rate
@@@ -2242,6 -2331,7 +2327,7 @@@ GstDiscovererStreamInf
  GstDiscovererContainerInfo
  GstDiscovererAudioInfo
  GstDiscovererVideoInfo
+ GstDiscovererSubtitleInfo
  gst_discoverer_stream_info_get_caps
  gst_discoverer_stream_info_get_misc
  gst_discoverer_stream_info_get_next
@@@ -2283,6 -2373,7 +2369,7 @@@ GST_DISCOVERER_CONTAINER_INF
  GST_DISCOVERER_INFO
  GST_DISCOVERER_STREAM_INFO
  GST_DISCOVERER_VIDEO_INFO
+ GST_DISCOVERER_SUBTITLE_INFO
  GST_IS_DISCOVERER
  GST_IS_DISCOVERER_INFO
  GST_IS_DISCOVERER_AUDIO_INFO
@@@ -2290,6 -2381,7 +2377,7 @@@ GST_IS_DISCOVERER_CLAS
  GST_IS_DISCOVERER_CONTAINER_INFO
  GST_IS_DISCOVERER_STREAM_INFO
  GST_IS_DISCOVERER_VIDEO_INFO
+ GST_IS_DISCOVERER_SUBTITLE_INFO
  GST_TYPE_DISCOVERER
  GST_TYPE_DISCOVERER_AUDIO_INFO
  GST_TYPE_DISCOVERER_CONTAINER_INFO
@@@ -2297,12 -2389,14 +2385,14 @@@ GST_TYPE_DISCOVERER_INF
  GST_TYPE_DISCOVERER_RESULT
  GST_TYPE_DISCOVERER_STREAM_INFO
  GST_TYPE_DISCOVERER_VIDEO_INFO
+ GST_TYPE_DISCOVERER_SUBTITLE_INFO
  GstDiscovererAudioInfoClass
  GstDiscovererClass
  GstDiscovererContainerInfoClass
  GstDiscovererPrivate
  GstDiscovererStreamInfoClass
  GstDiscovererVideoInfoClass
+ GstDiscovererSubtitleInfoClass
  GstDiscovererInfoClass
  gst_discoverer_audio_info_get_type
  gst_discoverer_container_info_get_type
@@@ -3,6 -3,10 +3,10 @@@
  
  #include <gst/audio/gstaudioclock.h>
  gst_audio_clock_get_type
+ #include <gst/audio/gstaudiodecoder.h>
+ gst_audio_decoder_get_type
+ #include <gst/audio/gstaudioencoder.h>
+ gst_audio_encoder_get_type
  #include <gst/audio/gstaudiofilter.h>
  gst_audio_filter_get_type
  #include <gst/audio/gstaudiosink.h>
@@@ -40,8 -44,8 +44,8 @@@ gst_tuner_norm_get_typ
  gst_stream_volume_get_type
  #include <gst/interfaces/videoorientation.h>
  gst_video_orientation_get_type
 -#include <gst/interfaces/xoverlay.h>
 -gst_x_overlay_get_type
 +#include <gst/interfaces/videooverlay.h>
 +gst_video_overlay_get_type
  
  
  #include <gst/rtp/gstbasertpdepayload.h>
@@@ -16,14 -16,15 +16,15 @@@ lib_LTLIBRARIES = 
  
  CLEANFILES = $(BUILT_SOURCES)
  
+ # FIXME 0.11: rename GstBaseAudioSink to GstAudioBaseSink or merge with GstAudioSink
  libgstaudio_@GST_MAJORMINOR@_la_SOURCES = \
        audio.c \
        gstringbuffer.c \
        gstaudioclock.c \
        mixerutils.c \
        multichannel.c \
-       gstbaseaudiodecoder.c \
-       gstbaseaudioencoder.c \
+       gstaudiodecoder.c \
+       gstaudioencoder.c \
        gstbaseaudiosink.c \
        gstbaseaudiosrc.c \
        gstaudiofilter.c \
@@@ -38,8 -39,8 +39,8 @@@ libgstaudio_@GST_MAJORMINOR@include_HEA
        gstringbuffer.h \
        gstaudioclock.h \
        gstaudiofilter.h \
-       gstbaseaudiodecoder.h \
-       gstbaseaudioencoder.h \
+       gstaudiodecoder.h \
+       gstaudioencoder.h \
        gstbaseaudiosink.h \
        gstbaseaudiosrc.h \
        gstaudiosink.h \
@@@ -74,7 -75,6 +75,7 @@@ GstAudio-@GST_MAJORMINOR@.gir: $(INTROS
                GST_PLUGIN_SYSTEM_PATH="" GST_PLUGIN_PATH="" GST_REGISTRY_UPDATE=no \
                $(INTROSPECTION_SCANNER) -v --namespace GstAudio \
                --nsversion=@GST_MAJORMINOR@ \
 +              --warn-all \
                --strip-prefix=Gst \
                -DGST_USE_UNSTABLE_API \
                -I$(top_srcdir)/gst-libs \
@@@ -1,7 -1,6 +1,7 @@@
  /* GStreamer
   * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
   * Library       <2001> Thomas Vander Stichele <thomas@apestaart.org>
 + *               <2011> Wim Taymans <wim.taymans@gmail.com>
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Library General Public
@@@ -33,36 -32,38 +33,36 @@@ G_BEGIN_DECL
   * @GST_AUDIO_FORMAT_UNKNOWN: unknown audio format
   * @GST_AUDIO_FORMAT_S8: sample
   * @GST_AUDIO_FORMAT_U8: sample
 - * @GST_AUDIO_FORMAT_S16_LE: sample
 - * @GST_AUDIO_FORMAT_S16_BE: sample
 - * @GST_AUDIO_FORMAT_U16_LE: sample
 - * @GST_AUDIO_FORMAT_U16_BE: sample
 - * @GST_AUDIO_FORMAT_S24_LE: sample
 - * @GST_AUDIO_FORMAT_S24_BE: sample
 - * @GST_AUDIO_FORMAT_U24_LE: sample
 - * @GST_AUDIO_FORMAT_U24_BE: sample
 - * @GST_AUDIO_FORMAT_S32_LE: sample
 - * @GST_AUDIO_FORMAT_S32_BE: sample
 - * @GST_AUDIO_FORMAT_U32_LE: sample
 - * @GST_AUDIO_FORMAT_U32_BE: sample
 - * @GST_AUDIO_FORMAT_S24_3LE: sample
 - * @GST_AUDIO_FORMAT_S24_3BE: sample
 - * @GST_AUDIO_FORMAT_U24_3LE: sample
 - * @GST_AUDIO_FORMAT_U24_3BE: sample
 - * @GST_AUDIO_FORMAT_S20_3LE: sample
 - * @GST_AUDIO_FORMAT_S20_3BE: sample
 - * @GST_AUDIO_FORMAT_U20_3LE: sample
 - * @GST_AUDIO_FORMAT_U20_3BE: sample
 - * @GST_AUDIO_FORMAT_S18_3LE: sample
 - * @GST_AUDIO_FORMAT_S18_3BE: sample
 - * @GST_AUDIO_FORMAT_U18_3LE: sample
 - * @GST_AUDIO_FORMAT_U18_3BE: sample
 - * @GST_AUDIO_FORMAT_F32_LE: sample
 - * @GST_AUDIO_FORMAT_F32_BE: sample
 - * @GST_AUDIO_FORMAT_F64_LE: sample
 - * @GST_AUDIO_FORMAT_F64_BE: sample
 + * @GST_AUDIO_FORMAT_S16LE: sample
 + * @GST_AUDIO_FORMAT_S16BE: sample
 + * @GST_AUDIO_FORMAT_U16LE: sample
 + * @GST_AUDIO_FORMAT_U16BE: sample
 + * @GST_AUDIO_FORMAT_S24_32LE: sample
 + * @GST_AUDIO_FORMAT_S24_32BE: sample
 + * @GST_AUDIO_FORMAT_U24_32LE: sample
 + * @GST_AUDIO_FORMAT_U24_32BE: sample
 + * @GST_AUDIO_FORMAT_S32LE: sample
 + * @GST_AUDIO_FORMAT_S32BE: sample
 + * @GST_AUDIO_FORMAT_U32LE: sample
 + * @GST_AUDIO_FORMAT_U32BE: sample
 + * @GST_AUDIO_FORMAT_S24LE: sample
 + * @GST_AUDIO_FORMAT_S24BE: sample
 + * @GST_AUDIO_FORMAT_U24LE: sample
 + * @GST_AUDIO_FORMAT_U24BE: sample
 + * @GST_AUDIO_FORMAT_S20LE: sample
 + * @GST_AUDIO_FORMAT_S20BE: sample
 + * @GST_AUDIO_FORMAT_U20LE: sample
 + * @GST_AUDIO_FORMAT_U20BE: sample
 + * @GST_AUDIO_FORMAT_S18LE: sample
 + * @GST_AUDIO_FORMAT_S18BE: sample
 + * @GST_AUDIO_FORMAT_U18LE: sample
 + * @GST_AUDIO_FORMAT_U18BE: sample
 + * @GST_AUDIO_FORMAT_F32LE: sample
 + * @GST_AUDIO_FORMAT_F32BE: sample
 + * @GST_AUDIO_FORMAT_F64LE: sample
 + * @GST_AUDIO_FORMAT_F64BE: sample
   *
   * Enum value describing the most common audio formats.
 - *
 - * Since: 0.10.36
   */
  typedef enum {
    GST_AUDIO_FORMAT_UNKNOWN,
    GST_AUDIO_FORMAT_S8,
    GST_AUDIO_FORMAT_U8,
    /* 16 bit */
 -  GST_AUDIO_FORMAT_S16_LE,
 -  GST_AUDIO_FORMAT_S16_BE,
 -  GST_AUDIO_FORMAT_U16_LE,
 -  GST_AUDIO_FORMAT_U16_BE,
 +  GST_AUDIO_FORMAT_S16LE,
 +  GST_AUDIO_FORMAT_S16BE,
 +  GST_AUDIO_FORMAT_U16LE,
 +  GST_AUDIO_FORMAT_U16BE,
    /* 24 bit in low 3 bytes of 32 bits*/
 -  GST_AUDIO_FORMAT_S24_LE,
 -  GST_AUDIO_FORMAT_S24_BE,
 -  GST_AUDIO_FORMAT_U24_LE,
 -  GST_AUDIO_FORMAT_U24_BE,
 +  GST_AUDIO_FORMAT_S24_32LE,
 +  GST_AUDIO_FORMAT_S24_32BE,
 +  GST_AUDIO_FORMAT_U24_32LE,
 +  GST_AUDIO_FORMAT_U24_32BE,
    /* 32 bit */
 -  GST_AUDIO_FORMAT_S32_LE,
 -  GST_AUDIO_FORMAT_S32_BE,
 -  GST_AUDIO_FORMAT_U32_LE,
 -  GST_AUDIO_FORMAT_U32_BE,
 +  GST_AUDIO_FORMAT_S32LE,
 +  GST_AUDIO_FORMAT_S32BE,
 +  GST_AUDIO_FORMAT_U32LE,
 +  GST_AUDIO_FORMAT_U32BE,
    /* 24 bit in 3 bytes*/
 -  GST_AUDIO_FORMAT_S24_3LE,
 -  GST_AUDIO_FORMAT_S24_3BE,
 -  GST_AUDIO_FORMAT_U24_3LE,
 -  GST_AUDIO_FORMAT_U24_3BE,
 +  GST_AUDIO_FORMAT_S24LE,
 +  GST_AUDIO_FORMAT_S24BE,
 +  GST_AUDIO_FORMAT_U24LE,
 +  GST_AUDIO_FORMAT_U24BE,
    /* 20 bit in 3 bytes*/
 -  GST_AUDIO_FORMAT_S20_3LE,
 -  GST_AUDIO_FORMAT_S20_3BE,
 -  GST_AUDIO_FORMAT_U20_3LE,
 -  GST_AUDIO_FORMAT_U20_3BE,
 +  GST_AUDIO_FORMAT_S20LE,
 +  GST_AUDIO_FORMAT_S20BE,
 +  GST_AUDIO_FORMAT_U20LE,
 +  GST_AUDIO_FORMAT_U20BE,
    /* 18 bit in 3 bytes*/
 -  GST_AUDIO_FORMAT_S18_3LE,
 -  GST_AUDIO_FORMAT_S18_3BE,
 -  GST_AUDIO_FORMAT_U18_3LE,
 -  GST_AUDIO_FORMAT_U18_3BE,
 +  GST_AUDIO_FORMAT_S18LE,
 +  GST_AUDIO_FORMAT_S18BE,
 +  GST_AUDIO_FORMAT_U18LE,
 +  GST_AUDIO_FORMAT_U18BE,
    /* float */
 -  GST_AUDIO_FORMAT_F32_LE,
 -  GST_AUDIO_FORMAT_F32_BE,
 -  GST_AUDIO_FORMAT_F64_LE,
 -  GST_AUDIO_FORMAT_F64_BE,
 +  GST_AUDIO_FORMAT_F32LE,
 +  GST_AUDIO_FORMAT_F32BE,
 +  GST_AUDIO_FORMAT_F64LE,
 +  GST_AUDIO_FORMAT_F64BE,
  #if G_BYTE_ORDER == G_BIG_ENDIAN
 -  GST_AUDIO_FORMAT_S16 = GST_AUDIO_FORMAT_S16_BE,
 -  GST_AUDIO_FORMAT_U16 = GST_AUDIO_FORMAT_U16_BE,
 -  GST_AUDIO_FORMAT_S24 = GST_AUDIO_FORMAT_S24_BE,
 -  GST_AUDIO_FORMAT_U24 = GST_AUDIO_FORMAT_U24_BE,
 -  GST_AUDIO_FORMAT_S32 = GST_AUDIO_FORMAT_S32_BE,
 -  GST_AUDIO_FORMAT_U32 = GST_AUDIO_FORMAT_U32_BE,
 -  GST_AUDIO_FORMAT_S24_3 = GST_AUDIO_FORMAT_S24_3BE,
 -  GST_AUDIO_FORMAT_U24_3 = GST_AUDIO_FORMAT_U24_3BE,
 -  GST_AUDIO_FORMAT_S20_3 = GST_AUDIO_FORMAT_S20_3BE,
 -  GST_AUDIO_FORMAT_U20_3 = GST_AUDIO_FORMAT_U20_3BE,
 -  GST_AUDIO_FORMAT_S18_3 = GST_AUDIO_FORMAT_S18_3BE,
 -  GST_AUDIO_FORMAT_U18_3 = GST_AUDIO_FORMAT_U18_3BE,
 -  GST_AUDIO_FORMAT_F32 = GST_AUDIO_FORMAT_F32_BE,
 -  GST_AUDIO_FORMAT_F64 = GST_AUDIO_FORMAT_F64_BE
 +  GST_AUDIO_FORMAT_S16 = GST_AUDIO_FORMAT_S16BE,
 +  GST_AUDIO_FORMAT_U16 = GST_AUDIO_FORMAT_U16BE,
 +  GST_AUDIO_FORMAT_S24_32 = GST_AUDIO_FORMAT_S24_32BE,
 +  GST_AUDIO_FORMAT_U24_32 = GST_AUDIO_FORMAT_U24_32BE,
 +  GST_AUDIO_FORMAT_S32 = GST_AUDIO_FORMAT_S32BE,
 +  GST_AUDIO_FORMAT_U32 = GST_AUDIO_FORMAT_U32BE,
 +  GST_AUDIO_FORMAT_S24 = GST_AUDIO_FORMAT_S24BE,
 +  GST_AUDIO_FORMAT_U24 = GST_AUDIO_FORMAT_U24BE,
 +  GST_AUDIO_FORMAT_S20 = GST_AUDIO_FORMAT_S20BE,
 +  GST_AUDIO_FORMAT_U20 = GST_AUDIO_FORMAT_U20BE,
 +  GST_AUDIO_FORMAT_S18 = GST_AUDIO_FORMAT_S18BE,
 +  GST_AUDIO_FORMAT_U18 = GST_AUDIO_FORMAT_U18BE,
 +  GST_AUDIO_FORMAT_F32 = GST_AUDIO_FORMAT_F32BE,
 +  GST_AUDIO_FORMAT_F64 = GST_AUDIO_FORMAT_F64BE
  #elif G_BYTE_ORDER == G_LITTLE_ENDIAN
 -  GST_AUDIO_FORMAT_S16 = GST_AUDIO_FORMAT_S16_LE,
 -  GST_AUDIO_FORMAT_U16 = GST_AUDIO_FORMAT_U16_LE,
 -  GST_AUDIO_FORMAT_S24 = GST_AUDIO_FORMAT_S24_LE,
 -  GST_AUDIO_FORMAT_U24 = GST_AUDIO_FORMAT_U24_LE,
 -  GST_AUDIO_FORMAT_S32 = GST_AUDIO_FORMAT_S32_LE,
 -  GST_AUDIO_FORMAT_U32 = GST_AUDIO_FORMAT_U32_LE,
 -  GST_AUDIO_FORMAT_S24_3 = GST_AUDIO_FORMAT_S24_3LE,
 -  GST_AUDIO_FORMAT_U24_3 = GST_AUDIO_FORMAT_U24_3LE,
 -  GST_AUDIO_FORMAT_S20_3 = GST_AUDIO_FORMAT_S20_3LE,
 -  GST_AUDIO_FORMAT_U20_3 = GST_AUDIO_FORMAT_U20_3LE,
 -  GST_AUDIO_FORMAT_S18_3 = GST_AUDIO_FORMAT_S18_3LE,
 -  GST_AUDIO_FORMAT_U18_3 = GST_AUDIO_FORMAT_U18_3LE,
 -  GST_AUDIO_FORMAT_F32 = GST_AUDIO_FORMAT_F32_LE,
 -  GST_AUDIO_FORMAT_F64 = GST_AUDIO_FORMAT_F64_LE
 +  GST_AUDIO_FORMAT_S16 = GST_AUDIO_FORMAT_S16LE,
 +  GST_AUDIO_FORMAT_U16 = GST_AUDIO_FORMAT_U16LE,
 +  GST_AUDIO_FORMAT_S24_32 = GST_AUDIO_FORMAT_S24_32LE,
 +  GST_AUDIO_FORMAT_U24_32 = GST_AUDIO_FORMAT_U24_32LE,
 +  GST_AUDIO_FORMAT_S32 = GST_AUDIO_FORMAT_S32LE,
 +  GST_AUDIO_FORMAT_U32 = GST_AUDIO_FORMAT_U32LE,
 +  GST_AUDIO_FORMAT_S24 = GST_AUDIO_FORMAT_S24LE,
 +  GST_AUDIO_FORMAT_U24 = GST_AUDIO_FORMAT_U24LE,
 +  GST_AUDIO_FORMAT_S20 = GST_AUDIO_FORMAT_S20LE,
 +  GST_AUDIO_FORMAT_U20 = GST_AUDIO_FORMAT_U20LE,
 +  GST_AUDIO_FORMAT_S18 = GST_AUDIO_FORMAT_S18LE,
 +  GST_AUDIO_FORMAT_U18 = GST_AUDIO_FORMAT_U18LE,
 +  GST_AUDIO_FORMAT_F32 = GST_AUDIO_FORMAT_F32LE,
 +  GST_AUDIO_FORMAT_F64 = GST_AUDIO_FORMAT_F64LE
  #endif
  } GstAudioFormat;
  
 -/* FIXME: need GTypes */
  typedef struct _GstAudioFormatInfo GstAudioFormatInfo;
  typedef struct _GstAudioInfo GstAudioInfo;
  
   * @GST_AUDIO_FORMAT_FLAG_COMPLEX: complex layout
   *
   * The different audio flags that a format info can have.
 - *
 - * Since: 0.10.36
   */
  typedef enum
  {
  } GstAudioFormatFlags;
  
  /**
 + * GstAudioFormatUnpack:
 + * @info: a #GstAudioFormatInfo
 + * @dest: a destination array
 + * @data: pointer to the audio data
 + * @length: the amount of samples to unpack.
 + *
 + * Unpacks @length samples from the given data of format @info.
 + * The samples will be unpacked into @dest which each channel
 + * interleaved. @dest should at least be big enough to hold @length *
 + * channels * size(unpack_format) bytes.
 + */
 +typedef void (*GstAudioFormatUnpack)         (GstAudioFormatInfo *info, gpointer dest,
 +                                              const gpointer data, gint length);
 +/**
 + * GstAudioFormatPack:
 + * @info: a #GstAudioFormatInfo
 + * @src: a source array
 + * @data: pointer to the destination data
 + * @length: the amount of samples to pack.
 + *
 + * Packs @length samples from @src to the data array in format @info.
 + * The samples from source have each channel interleaved
 + * and will be packed into @data.
 + */
 +typedef void (*GstAudioFormatPack)           (GstAudioFormatInfo *info, const gpointer src,
 +                                              gpointer data, gint length);
 +
 +/**
   * GstAudioFormatInfo:
   * @format: #GstAudioFormat
   * @name: string representation of the format
   * @width: amount of bits used for one sample
   * @depth: amount of valid bits in @width
   * @silence: @width/8 bytes with 1 silent sample
 + * @unpack_format: the format of the unpacked samples
 + * @unpack_func: function to unpack samples
 + * @pack_func: function to pack samples
   *
   * Information for an audio format.
 - *
 - * Since: 0.10.36
   */
  struct _GstAudioFormatInfo {
 -  GstAudioFormat      format;
 -  const gchar *       name;
 +  GstAudioFormat format;
 +  const gchar *name;
    GstAudioFormatFlags flags;
 -  gint                endianness;
 -  gint                width;
 -  gint                depth;
 -  guint8              silence[8];
 -  /*< private >*/
 -  guint               padding_i[4];
 -  gpointer            padding_p[4];
 +  gint endianness;
 +  gint width;
 +  gint depth;
 +  guint8 silence[8];
 +
 +  GstAudioFormat unpack_format;
 +  GstAudioFormatUnpack unpack_func;
 +  GstAudioFormatPack pack_func;
  };
  
  #define GST_AUDIO_FORMAT_INFO_FORMAT(info)       ((info)->format)
  #define GST_AUDIO_FORMAT_INFO_NAME(info)         ((info)->name)
  #define GST_AUDIO_FORMAT_INFO_FLAGS(info)        ((info)->flags)
  
- #define GST_AUDIO_FORMAT_INFO_IS_INTEGER(info)   ((info)->flags & GST_AUDIO_FORMAT_FLAG_INTEGER)
- #define GST_AUDIO_FORMAT_INFO_IS_FLOAT(info)     ((info)->flags & GST_AUDIO_FORMAT_FLAG_FLOAT)
- #define GST_AUDIO_FORMAT_INFO_IS_SIGNED(info)    ((info)->flags & GST_AUDIO_FORMAT_FLAG_SIGNED)
+ #define GST_AUDIO_FORMAT_INFO_IS_INTEGER(info)   !!((info)->flags & GST_AUDIO_FORMAT_FLAG_INTEGER)
+ #define GST_AUDIO_FORMAT_INFO_IS_FLOAT(info)     !!((info)->flags & GST_AUDIO_FORMAT_FLAG_FLOAT)
+ #define GST_AUDIO_FORMAT_INFO_IS_SIGNED(info)    !!((info)->flags & GST_AUDIO_FORMAT_FLAG_SIGNED)
  
  #define GST_AUDIO_FORMAT_INFO_ENDIANNESS(info)   ((info)->endianness)
  #define GST_AUDIO_FORMAT_INFO_IS_LE(info)        ((info)->endianness == G_LITTLE_ENDIAN)
  #define GST_AUDIO_FORMAT_INFO_WIDTH(info)        ((info)->width)
  #define GST_AUDIO_FORMAT_INFO_DEPTH(info)        ((info)->depth)
  
 -const GstAudioFormatInfo * gst_audio_format_get_info (GstAudioFormat format) G_GNUC_CONST;
  
 +GstAudioFormat gst_audio_format_build_integer    (gboolean sign, gint endianness,
 +                                                  gint width, gint depth) G_GNUC_CONST;
 +
 +GstAudioFormat gst_audio_format_from_string      (const gchar *format) G_GNUC_CONST;
 +const gchar *  gst_audio_format_to_string        (GstAudioFormat format) G_GNUC_CONST;
 +
 +const GstAudioFormatInfo *
 +               gst_audio_format_get_info         (GstAudioFormat format) G_GNUC_CONST;
 +
 +void           gst_audio_format_fill_silence     (const GstAudioFormatInfo *info,
 +                                                  gpointer dest, gsize length);
  /**
   * GstAudioFlags:
   * @GST_AUDIO_FLAG_NONE: no valid flag
 - * @GST_AUDIO_FLAG_DEFAULT_POSITIONS: unpositioned audio layout, position array
 - *     contains the default layout (meaning that the channel layout was not
 - *     explicitly specified in the caps)
 + * @GST_AUDIO_FLAG_DEFAULT_POSITIONS: position array
 + *     contains the default layout for the number of channels.
   *
   * Extra audio flags
 - *
 - * Since: 0.10.36
   */
  typedef enum {
 -  GST_AUDIO_FLAG_NONE         = 0,
 +  GST_AUDIO_FLAG_NONE              = 0,
    GST_AUDIO_FLAG_DEFAULT_POSITIONS = (1 << 0)
  } GstAudioFlags;
  
   * in from GstCaps with gst_audio_info_from_caps().
   *
   * Use the provided macros to access the info in this structure.
 - *
 - * Since: 0.10.36
   */
  struct _GstAudioInfo {
    const GstAudioFormatInfo *finfo;
  #define GST_AUDIO_INFO_BPF(info)             ((info)->bpf)
  #define GST_AUDIO_INFO_POSITION(info,c)      ((info)->position[c])
  
 -void           gst_audio_info_init  (GstAudioInfo * info);
 -void           gst_audio_info_clear (GstAudioInfo * info);
 +void         gst_audio_info_init        (GstAudioInfo *info);
 +void         gst_audio_info_set_format  (GstAudioInfo *info, GstAudioFormat format,
 +                                         gint rate, gint channels);
  
 -GstAudioInfo * gst_audio_info_copy  (GstAudioInfo * info);
 -void           gst_audio_info_free  (GstAudioInfo * info);
 +gboolean     gst_audio_info_from_caps   (GstAudioInfo *info, const GstCaps *caps);
 +GstCaps *    gst_audio_info_to_caps     (GstAudioInfo *info);
  
 -gboolean       gst_audio_info_from_caps (GstAudioInfo * info, const GstCaps * caps);
 -GstCaps *      gst_audio_info_to_caps   (GstAudioInfo * info);
 -
 -gboolean       gst_audio_info_convert   (GstAudioInfo * info,
 -                                         GstFormat src_fmt,  gint64   src_val,
 +gboolean     gst_audio_info_convert     (GstAudioInfo * info,
 +                                         GstFormat src_fmt, gint64 src_val,
                                           GstFormat dest_fmt, gint64 * dest_val);
  
 -/* For people that are looking at this source: the purpose of these defines is
 - * to make GstCaps a bit easier, in that you don't have to know all of the
 - * properties that need to be defined. you can just use these macros. currently
 - * (8/01) the only plugins that use these are the passthrough, speed, volume,
 - * adder, and [de]interleave plugins. These are for convenience only, and do not
 - * specify the 'limits' of GStreamer. you might also use these definitions as a
 - * base for making your own caps, if need be.
 +
 +
 +#define GST_AUDIO_RATE_RANGE "(int) [ 1, max ]"
 +#define GST_AUDIO_CHANNELS_RANGE "(int) [ 1, max ]"
 +
 +#if G_BYTE_ORDER == G_LITTLE_ENDIAN
 +# define GST_AUDIO_NE(s) G_STRINGIFY(s)"LE"
 +# define GST_AUDIO_OE(s) G_STRINGIFY(s)"BE"
 +#else
 +# define GST_AUDIO_NE(s) G_STRINGIFY(s)"BE"
 +# define GST_AUDIO_OE(s) G_STRINGIFY(s)"LE"
 +#endif
 +
 +#define GST_AUDIO_FORMATS_ALL " { S8, U8, " \
 +    "S16LE, S16BE, U16LE, U16BE, " \
 +    "S24_32LE, S24_32BE, U24_32LE, U24_32BE, " \
 +    "S32LE, S32BE, U32LE, U32BE, " \
 +    "S24LE, S24BE, U24LE, U24BE, " \
 +    "S20LE, S20BE, U20LE, U20BE, " \
 +    "S18LE, S18BE, U18LE, U18BE, " \
 +    "F32LE, F32BE, F64LE, F64BE }"
 +
 +/**
 + * GST_AUDIO_CAPS_MAKE:
 + * @format: string format that describes the pixel layout, as string
 + *     (e.g. "S16LE", "S8", etc.)
   *
 - * For example, to make a source pad that can output streams of either mono
 - * float or any channel int:
 + * Generic caps string for audio, for use in pad templates.
 + */
 +#define GST_AUDIO_CAPS_MAKE(format)                                    \
 +    "audio/x-raw, "                                                    \
 +    "format = (string) " format ", "                                   \
 +    "rate = " GST_AUDIO_RATE_RANGE ", "                                \
 +    "channels = " GST_AUDIO_CHANNELS_RANGE
 +
 +/**
 + * GST_AUDIO_DEF_RATE:
   *
 - *  template = gst_pad_template_new
 - *    ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
 - *    gst_caps_append(gst_caps_new ("sink_int",  "audio/x-raw-int",
 - *                                  GST_AUDIO_INT_PAD_TEMPLATE_PROPS),
 - *                    gst_caps_new ("sink_float", "audio/x-raw-float",
 - *                                  GST_AUDIO_FLOAT_PAD_TEMPLATE_PROPS)),
 - *    NULL);
 + * Standard sampling rate used in consumer audio.
 + */
 +#define GST_AUDIO_DEF_RATE 44100
 +/**
 + * GST_AUDIO_DEF_CHANNELS:
   *
 - *  sinkpad = gst_pad_new_from_template(template, "sink");
 + * Standard number of channels used in consumer audio.
 + */
 +#define GST_AUDIO_DEF_CHANNELS 2
 +/**
 + * GST_AUDIO_DEF_FORMAT:
   *
 - * Andy Wingo, 18 August 2001
 - * Thomas, 6 September 2002 */
 + * Standard format used in consumer audio.
 + */
 +#define GST_AUDIO_DEF_FORMAT "S16LE"
  
  /* conversion macros */
  /**
   * GST_FRAMES_TO_CLOCK_TIME:
   * @frames: sample frames
   * @rate: sampling rate
 - * 
 + *
   * Calculate clocktime from sample @frames and @rate.
   */
  #define GST_FRAMES_TO_CLOCK_TIME(frames, rate) \
   * GST_CLOCK_TIME_TO_FRAMES:
   * @clocktime: clock time
   * @rate: sampling rate
 - * 
 + *
   * Calculate frames from @clocktime and sample @rate.
   */
  #define GST_CLOCK_TIME_TO_FRAMES(clocktime, rate) \
    gst_util_uint64_scale_round (clocktime, rate, GST_SECOND)
  
 -/**
 - * GST_AUDIO_DEF_RATE:
 - * 
 - * Standard sampling rate used in consumer audio.
 - */
 -#define GST_AUDIO_DEF_RATE 44100
 -
 -/**
 - * GST_AUDIO_INT_PAD_TEMPLATE_CAPS:
 - * 
 - * Template caps for integer audio. Can be used when defining a 
 - * #GstStaticPadTemplate
 - */
 -#define GST_AUDIO_INT_PAD_TEMPLATE_CAPS \
 -  "audio/x-raw-int, " \
 -  "rate = (int) [ 1, MAX ], " \
 -  "channels = (int) [ 1, MAX ], " \
 -  "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
 -  "width = (int) { 8, 16, 24, 32 }, " \
 -  "depth = (int) [ 1, 32 ], " \
 -  "signed = (boolean) { true, false }"
 -
 -/**
 - * GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS:
 - * 
 - * Template caps for 16bit integer stereo audio in native byte-order.
 - * Can be used when defining a #GstStaticPadTemplate
 - */
 -#define GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS \
 -  "audio/x-raw-int, " \
 -  "rate = (int) [ 1, MAX ], " \
 -  "channels = (int) 2, " \
 -  "endianness = (int) BYTE_ORDER, " \
 -  "width = (int) 16, " \
 -  "depth = (int) 16, " \
 -  "signed = (boolean) true"
 -
 -/**
 - * GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS:
 - * 
 - * Template caps for float audio. Can be used when defining a 
 - * #GstStaticPadTemplate
 - */
 -#define GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS \
 -  "audio/x-raw-float, " \
 -  "rate = (int) [ 1, MAX ], " \
 -  "channels = (int) [ 1, MAX ], " \
 -  "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, " \
 -  "width = (int) { 32, 64 }"
 -
 -/**
 - * GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS:
 - * 
 - * Template caps for 32bit float mono audio in native byte-order.
 - * Can be used when defining a #GstStaticPadTemplate
 - */
 -#define GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS \
 -  "audio/x-raw-float, " \
 -  "width = (int) 32, " \
 -  "rate = (int) [ 1, MAX ], " \
 -  "channels = (int) 1, " \
 -  "endianness = (int) BYTE_ORDER"
 -
  /*
   * this library defines and implements some helper functions for audio
   * handling
   */
  
 -/* get byte size of audio frame (based on caps of pad */
 -int      gst_audio_frame_byte_size      (GstPad* pad);
 -
 -/* get length in frames of buffer */
 -long     gst_audio_frame_length         (GstPad* pad, GstBuffer* buf);
 -
 -GstClockTime gst_audio_duration_from_pad_buffer (GstPad * pad, GstBuffer * buf);
 -
 -/* check if the buffer size is a whole multiple of the frame size */
 -gboolean gst_audio_is_buffer_framed     (GstPad* pad, GstBuffer* buf);
 -
 -/* functions useful for _getcaps functions */
 -/**
 - * GstAudioFieldFlag:
 - * @GST_AUDIO_FIELD_RATE: add rate field to caps
 - * @GST_AUDIO_FIELD_CHANNELS: add channels field to caps
 - * @GST_AUDIO_FIELD_ENDIANNESS: add endianness field to caps
 - * @GST_AUDIO_FIELD_WIDTH: add width field to caps
 - * @GST_AUDIO_FIELD_DEPTH: add depth field to caps
 - * @GST_AUDIO_FIELD_SIGNED: add signed field to caps
 - *
 - * Do not use anymore.
 - *
 - * Deprecated: use gst_structure_set() directly
 - */
 -#ifndef GST_DISABLE_DEPRECATED
 -typedef enum {
 -  GST_AUDIO_FIELD_RATE          = (1 << 0),
 -  GST_AUDIO_FIELD_CHANNELS      = (1 << 1),
 -  GST_AUDIO_FIELD_ENDIANNESS    = (1 << 2),
 -  GST_AUDIO_FIELD_WIDTH         = (1 << 3),
 -  GST_AUDIO_FIELD_DEPTH         = (1 << 4),
 -  GST_AUDIO_FIELD_SIGNED        = (1 << 5)
 -} GstAudioFieldFlag;
 -#endif
 -
 -#ifndef GST_DISABLE_DEPRECATED
 -void gst_audio_structure_set_int (GstStructure *structure, GstAudioFieldFlag flag);
 -#endif /* GST_DISABLE_DEPRECATED */
 -
 -GstBuffer *gst_audio_buffer_clip (GstBuffer *buffer, GstSegment *segment, gint rate, gint frame_size);
 +GstBuffer *    gst_audio_buffer_clip     (GstBuffer *buffer, GstSegment *segment,
 +                                          gint rate, gint bpf);
  
  G_END_DECLS
  
@@@ -22,7 -22,7 +22,7 @@@
   */
  
  /**
-  * SECTION:gstbaseaudiodecoder
+  * SECTION:gstaudiodecoder
   * @short_description: Base class for audio decoders
   * @see_also: #GstBaseTransform
   * @since: 0.10.36
   * This base class is for audio decoders turning encoded data into
   * raw audio samples.
   *
-  * GstBaseAudioDecoder and subclass should cooperate as follows.
+  * GstAudioDecoder and subclass should cooperate as follows.
   * <orderedlist>
   * <listitem>
   *   <itemizedlist><title>Configuration</title>
   *   <listitem><para>
-  *     Initially, GstBaseAudioDecoder calls @start when the decoder element
+  *     Initially, GstAudioDecoder calls @start when the decoder element
   *     is activated, which allows subclass to perform any global setup.
   *     Base class (context) parameters can already be set according to subclass
   *     capabilities (or possibly upon receive more information in subsequent
   *     @set_format).
   *   </para></listitem>
   *   <listitem><para>
-  *     GstBaseAudioDecoder calls @set_format to inform subclass of the format
+  *     GstAudioDecoder calls @set_format to inform subclass of the format
   *     of input audio data that it is about to receive.
   *     While unlikely, it might be called more than once, if changing input
   *     parameters require reconfiguration.
   *   </para></listitem>
   *   <listitem><para>
-  *     GstBaseAudioDecoder calls @stop at end of all processing.
+  *     GstAudioDecoder calls @stop at end of all processing.
   *   </para></listitem>
   *   </itemizedlist>
   * </listitem>
-  * As of configuration stage, and throughout processing, GstBaseAudioDecoder
+  * As of configuration stage, and throughout processing, GstAudioDecoder
   * provides various (context) parameters, e.g. describing the format of
   * output audio data (valid when output caps have been caps) or current parsing state.
   * Conversely, subclass can and should configure context to inform
@@@ -71,7 -71,7 +71,7 @@@
   *     </para></listitem>
   *     <listitem><para>
   *       If codec processing results in decoded data, subclass should call
-  *       @gst_base_audio_decoder_finish_frame to have decoded data pushed
+  *       @gst_audio_decoder_finish_frame to have decoded data pushed
   *       downstream.
   *     </para></listitem>
   *     <listitem><para>
@@@ -82,7 -82,7 +82,7 @@@
   *       setting src pad caps.
   *     </para></listitem>
   *     <listitem><para>
-  *       During the parsing process GstBaseAudioDecoderClass will handle both
+  *       During the parsing process GstAudioDecoderClass will handle both
   *       srcpad and sinkpad events. Sink events will be passed to subclass
   *       if @event callback has been provided.
   *     </para></listitem>
@@@ -91,7 -91,7 +91,7 @@@
   * <listitem>
   *   <itemizedlist><title>Shutdown phase</title>
   *   <listitem><para>
-  *     GstBaseAudioDecoder class calls @stop to inform the subclass that data
+  *     GstAudioDecoder class calls @stop to inform the subclass that data
   *     parsing will be stopped.
   *   </para></listitem>
   *   </itemizedlist>
   * source and sink pads. The pads need to be named "sink" and "src". It also
   * needs to set the fixed caps on srcpad, when the format is ensured.  This
   * is typically when base class calls subclass' @set_format function, though
-  * it might be delayed until calling @gst_base_audio_decoder_finish_frame.
+  * it might be delayed until calling @gst_audio_decoder_finish_frame.
   *
   * In summary, above process should have subclass concentrating on
   * codec data processing while leaving other matters to base class,
   * In particular, base class will try to arrange for perfect output timestamps
   * as much as possible while tracking upstream timestamps.
   * To this end, if deviation between the next ideal expected perfect timestamp
-  * and upstream exceeds #GstBaseAudioDecoder:tolerance, then resync to upstream
+  * and upstream exceeds #GstAudioDecoder:tolerance, then resync to upstream
   * occurs (which would happen always if the tolerance mechanism is disabled).
   *
   * In non-live pipelines, baseclass can also (configurably) arrange for
   *   </para></listitem>
   *   <listitem><para>
   *      Accept data in @handle_frame and provide encoded results to
-  *      @gst_base_audio_decoder_finish_frame.  If it is prepared to perform
+  *      @gst_audio_decoder_finish_frame.  If it is prepared to perform
   *      PLC, it should also accept NULL data in @handle_frame and provide for
   *      data for indicated duration.
   *   </para></listitem>
  #include "config.h"
  #endif
  
- #include "gstbaseaudiodecoder.h"
 -#define GST_USE_UNSTABLE_API
+ #include "gstaudiodecoder.h"
  #include <gst/pbutils/descriptions.h>
  
  #include <string.h>
  
- GST_DEBUG_CATEGORY (baseaudiodecoder_debug);
- #define GST_CAT_DEFAULT baseaudiodecoder_debug
+ GST_DEBUG_CATEGORY (audiodecoder_debug);
+ #define GST_CAT_DEFAULT audiodecoder_debug
  
- #define GST_BASE_AUDIO_DECODER_GET_PRIVATE(obj)  \
-     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_DECODER, \
-         GstBaseAudioDecoderPrivate))
+ #define GST_AUDIO_DECODER_GET_PRIVATE(obj)  \
+     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_AUDIO_DECODER, \
+         GstAudioDecoderPrivate))
  
  enum
  {
@@@ -178,7 -179,7 +178,7 @@@ enu
  #define DEFAULT_TOLERANCE  0
  #define DEFAULT_PLC        FALSE
  
- typedef struct _GstBaseAudioDecoderContext
+ typedef struct _GstAudioDecoderContext
  {
    /* input */
    /* (output) audio format */
    /* MT-protected (with LOCK) */
    GstClockTime min_latency;
    GstClockTime max_latency;
- } GstBaseAudioDecoderContext;
+ } GstAudioDecoderContext;
  
- struct _GstBaseAudioDecoderPrivate
+ struct _GstAudioDecoderPrivate
  {
    /* activation status */
    gboolean active;
    GList *queued;
  
    /* context storage */
-   GstBaseAudioDecoderContext ctx;
+   GstAudioDecoderContext ctx;
  
    /* properties */
    GstClockTime latency;
  };
  
  
- static void gst_base_audio_decoder_finalize (GObject * object);
- static void gst_base_audio_decoder_set_property (GObject * object,
+ static void gst_audio_decoder_finalize (GObject * object);
+ static void gst_audio_decoder_set_property (GObject * object,
      guint prop_id, const GValue * value, GParamSpec * pspec);
- static void gst_base_audio_decoder_get_property (GObject * object,
+ static void gst_audio_decoder_get_property (GObject * object,
      guint prop_id, GValue * value, GParamSpec * pspec);
  
- static void gst_base_audio_decoder_clear_queues (GstBaseAudioDecoder * dec);
- static GstFlowReturn gst_base_audio_decoder_chain_reverse (GstBaseAudioDecoder *
+ static void gst_audio_decoder_clear_queues (GstAudioDecoder * dec);
+ static GstFlowReturn gst_audio_decoder_chain_reverse (GstAudioDecoder *
      dec, GstBuffer * buf);
  
- static GstStateChangeReturn gst_base_audio_decoder_change_state (GstElement *
+ static GstStateChangeReturn gst_audio_decoder_change_state (GstElement *
      element, GstStateChange transition);
- static gboolean gst_base_audio_decoder_sink_event (GstPad * pad,
-     GstEvent * event);
- static gboolean gst_base_audio_decoder_src_event (GstPad * pad,
-     GstEvent * event);
- static GstFlowReturn gst_base_audio_decoder_chain (GstPad * pad,
-     GstBuffer * buf);
- static gboolean gst_base_audio_decoder_src_query (GstPad * pad,
-     GstQuery * query);
- static gboolean gst_base_audio_decoder_sink_query (GstPad * pad,
-     GstQuery * query);
- static const GstQueryType *gst_base_audio_decoder_get_query_types (GstPad *
-     pad);
- static void gst_base_audio_decoder_reset (GstBaseAudioDecoder * dec,
-     gboolean full);
- #define gst_base_audio_decoder_parent_class parent_class
- G_DEFINE_TYPE (GstBaseAudioDecoder, gst_base_audio_decoder, GST_TYPE_ELEMENT);
+ static gboolean gst_audio_decoder_sink_event (GstPad * pad, GstEvent * event);
+ static gboolean gst_audio_decoder_src_event (GstPad * pad, GstEvent * event);
 -static gboolean gst_audio_decoder_sink_setcaps (GstPad * pad, GstCaps * caps);
 -static gboolean gst_audio_decoder_src_setcaps (GstPad * pad, GstCaps * caps);
++static gboolean gst_audio_decoder_sink_setcaps (GstAudioDecoder * dec,
++    GstCaps * caps);
++gboolean gst_audio_decoder_src_setcaps (GstAudioDecoder * dec, GstCaps * caps);
+ static GstFlowReturn gst_audio_decoder_chain (GstPad * pad, GstBuffer * buf);
+ static gboolean gst_audio_decoder_src_query (GstPad * pad, GstQuery * query);
+ static gboolean gst_audio_decoder_sink_query (GstPad * pad, GstQuery * query);
+ static const GstQueryType *gst_audio_decoder_get_query_types (GstPad * pad);
+ static void gst_audio_decoder_reset (GstAudioDecoder * dec, gboolean full);
 -GST_BOILERPLATE (GstAudioDecoder, gst_audio_decoder, GstElement,
 -    GST_TYPE_ELEMENT);
 -
 -static void
 -gst_audio_decoder_base_init (gpointer g_class)
 -{
 -}
++#define gst_audio_decoder_parent_class parent_class
++G_DEFINE_TYPE (GstAudioDecoder, gst_audio_decoder, GST_TYPE_ELEMENT);
  
  static void
- gst_base_audio_decoder_class_init (GstBaseAudioDecoderClass * klass)
+ gst_audio_decoder_class_init (GstAudioDecoderClass * klass)
  {
    GObjectClass *gobject_class;
    GstElementClass *element_class;
  
    parent_class = g_type_class_peek_parent (klass);
  
-   g_type_class_add_private (klass, sizeof (GstBaseAudioDecoderPrivate));
+   g_type_class_add_private (klass, sizeof (GstAudioDecoderPrivate));
  
-   GST_DEBUG_CATEGORY_INIT (baseaudiodecoder_debug, "baseaudiodecoder", 0,
-       "baseaudiodecoder element");
+   GST_DEBUG_CATEGORY_INIT (audiodecoder_debug, "audiodecoder", 0,
+       "audio decoder base class");
  
-   gobject_class->set_property = gst_base_audio_decoder_set_property;
-   gobject_class->get_property = gst_base_audio_decoder_get_property;
-   gobject_class->finalize = gst_base_audio_decoder_finalize;
+   gobject_class->set_property = gst_audio_decoder_set_property;
+   gobject_class->get_property = gst_audio_decoder_get_property;
+   gobject_class->finalize = gst_audio_decoder_finalize;
  
-   element_class->change_state = gst_base_audio_decoder_change_state;
+   element_class->change_state = gst_audio_decoder_change_state;
  
    /* Properties */
    g_object_class_install_property (gobject_class, PROP_LATENCY,
  }
  
  static void
- gst_base_audio_decoder_init (GstBaseAudioDecoder * dec)
 -gst_audio_decoder_init (GstAudioDecoder * dec, GstAudioDecoderClass * klass)
++gst_audio_decoder_init (GstAudioDecoder * dec)
  {
-   GstBaseAudioDecoderClass *klass = GST_BASE_AUDIO_DECODER_GET_CLASS (dec);
++  GstAudioDecoderClass *klass = GST_AUDIO_DECODER_GET_CLASS (dec);
    GstPadTemplate *pad_template;
  
-   GST_DEBUG_OBJECT (dec, "gst_base_audio_decoder_init");
+   GST_DEBUG_OBJECT (dec, "gst_audio_decoder_init");
  
-   dec->priv = GST_BASE_AUDIO_DECODER_GET_PRIVATE (dec);
+   dec->priv = GST_AUDIO_DECODER_GET_PRIVATE (dec);
  
    /* Setup sink pad */
    pad_template =
  
    dec->sinkpad = gst_pad_new_from_template (pad_template, "sink");
    gst_pad_set_event_function (dec->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_decoder_sink_event));
+       GST_DEBUG_FUNCPTR (gst_audio_decoder_sink_event));
 -  gst_pad_set_setcaps_function (dec->sinkpad,
 -      GST_DEBUG_FUNCPTR (gst_audio_decoder_sink_setcaps));
    gst_pad_set_chain_function (dec->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_decoder_chain));
+       GST_DEBUG_FUNCPTR (gst_audio_decoder_chain));
    gst_pad_set_query_function (dec->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_decoder_sink_query));
+       GST_DEBUG_FUNCPTR (gst_audio_decoder_sink_query));
    gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
    GST_DEBUG_OBJECT (dec, "sinkpad created");
  
    g_return_if_fail (pad_template != NULL);
  
    dec->srcpad = gst_pad_new_from_template (pad_template, "src");
 -  gst_pad_set_setcaps_function (dec->srcpad,
 -      GST_DEBUG_FUNCPTR (gst_audio_decoder_src_setcaps));
    gst_pad_set_event_function (dec->srcpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_decoder_src_event));
+       GST_DEBUG_FUNCPTR (gst_audio_decoder_src_event));
    gst_pad_set_query_function (dec->srcpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_decoder_src_query));
+       GST_DEBUG_FUNCPTR (gst_audio_decoder_src_query));
    gst_pad_set_query_type_function (dec->srcpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_decoder_get_query_types));
+       GST_DEBUG_FUNCPTR (gst_audio_decoder_get_query_types));
    gst_pad_use_fixed_caps (dec->srcpad);
    gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
    GST_DEBUG_OBJECT (dec, "srcpad created");
    dec->priv->plc = DEFAULT_PLC;
  
    /* init state */
-   gst_base_audio_decoder_reset (dec, TRUE);
+   gst_audio_decoder_reset (dec, TRUE);
    GST_DEBUG_OBJECT (dec, "init ok");
  }
  
  static void
- gst_base_audio_decoder_reset (GstBaseAudioDecoder * dec, gboolean full)
+ gst_audio_decoder_reset (GstAudioDecoder * dec, gboolean full)
  {
-   GST_DEBUG_OBJECT (dec, "gst_base_audio_decoder_reset");
+   GST_DEBUG_OBJECT (dec, "gst_audio_decoder_reset");
  
    GST_OBJECT_LOCK (dec);
  
      dec->priv->samples_out = 0;
      dec->priv->agg = -1;
      dec->priv->error_count = 0;
-     gst_base_audio_decoder_clear_queues (dec);
+     gst_audio_decoder_clear_queues (dec);
  
 -    gst_audio_info_clear (&dec->priv->ctx.info);
 +    gst_audio_info_init (&dec->priv->ctx.info);
      memset (&dec->priv->ctx, 0, sizeof (dec->priv->ctx));
  
      if (dec->priv->taglist) {
  }
  
  static void
- gst_base_audio_decoder_finalize (GObject * object)
+ gst_audio_decoder_finalize (GObject * object)
  {
-   GstBaseAudioDecoder *dec;
+   GstAudioDecoder *dec;
  
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (object));
-   dec = GST_BASE_AUDIO_DECODER (object);
+   g_return_if_fail (GST_IS_AUDIO_DECODER (object));
+   dec = GST_AUDIO_DECODER (object);
  
    if (dec->priv->adapter) {
      g_object_unref (dec->priv->adapter);
  
  /* automagically perform sanity checking of src caps;
   * also extracts output data format */
 -static gboolean
 -gst_audio_decoder_src_setcaps (GstPad * pad, GstCaps * caps)
 +gboolean
- gst_base_audio_decoder_src_setcaps (GstBaseAudioDecoder * dec, GstCaps * caps)
++gst_audio_decoder_src_setcaps (GstAudioDecoder * dec, GstCaps * caps)
  {
 -  GstAudioDecoder *dec;
    gboolean res = TRUE;
    guint old_rate;
  
 -  dec = GST_AUDIO_DECODER (gst_pad_get_parent (pad));
 -
    GST_DEBUG_OBJECT (dec, "setting src caps %" GST_PTR_FORMAT, caps);
  
    /* parse caps here to check subclass;
@@@ -487,12 -495,14 +484,12 @@@ refuse_caps
  }
  
  static gboolean
- gst_base_audio_decoder_sink_setcaps (GstBaseAudioDecoder * dec, GstCaps * caps)
 -gst_audio_decoder_sink_setcaps (GstPad * pad, GstCaps * caps)
++gst_audio_decoder_sink_setcaps (GstAudioDecoder * dec, GstCaps * caps)
  {
-   GstBaseAudioDecoderClass *klass;
 -  GstAudioDecoder *dec;
+   GstAudioDecoderClass *klass;
    gboolean res = TRUE;
  
-   klass = GST_BASE_AUDIO_DECODER_GET_CLASS (dec);
 -  dec = GST_AUDIO_DECODER (gst_pad_get_parent (pad));
+   klass = GST_AUDIO_DECODER_GET_CLASS (dec);
  
    GST_DEBUG_OBJECT (dec, "caps: %" GST_PTR_FORMAT, caps);
  
    if (klass->set_format)
      res = klass->set_format (dec, caps);
  
 -  g_object_unref (dec);
    return res;
  }
  
  static void
- gst_base_audio_decoder_setup (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_setup (GstAudioDecoder * dec)
  {
    GstQuery *query;
    gboolean res;
    gst_query_unref (query);
  
    /* normalize to bool */
 -  dec->priv->agg = ! !res;
 +  dec->priv->agg = !!res;
  }
  
  /* mini aggregator combining output buffers into fewer larger ones,
   * if so allowed/configured */
  static GstFlowReturn
- gst_base_audio_decoder_output (GstBaseAudioDecoder * dec, GstBuffer * buf)
+ gst_audio_decoder_output (GstAudioDecoder * dec, GstBuffer * buf)
  {
-   GstBaseAudioDecoderClass *klass;
-   GstBaseAudioDecoderPrivate *priv;
-   GstBaseAudioDecoderContext *ctx;
+   GstAudioDecoderClass *klass;
+   GstAudioDecoderPrivate *priv;
+   GstAudioDecoderContext *ctx;
    GstFlowReturn ret = GST_FLOW_OK;
    GstBuffer *inbuf = NULL;
  
-   klass = GST_BASE_AUDIO_DECODER_GET_CLASS (dec);
+   klass = GST_AUDIO_DECODER_GET_CLASS (dec);
    priv = dec->priv;
    ctx = &dec->priv->ctx;
  
    if (G_UNLIKELY (priv->agg < 0))
-     gst_base_audio_decoder_setup (dec);
+     gst_audio_decoder_setup (dec);
  
    if (G_LIKELY (buf)) {
      g_return_val_if_fail (ctx->info.bpf != 0, GST_FLOW_ERROR);
  
 -    GST_LOG_OBJECT (dec, "output buffer of size %d with ts %" GST_TIME_FORMAT
 -        ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
 +    GST_LOG_OBJECT (dec,
 +        "output buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT
 +        ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf),
          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
          GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
  
        GST_DEBUG_OBJECT (dec, "no data after clipping to segment");
      } else {
        GST_LOG_OBJECT (dec,
 -          "buffer after segment clipping has size %d with ts %" GST_TIME_FORMAT
 -          ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
 -          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
 +          "buffer after segment clipping has size %" G_GSIZE_FORMAT " with ts %"
 +          GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
 +          gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
            GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
      }
    } else {
@@@ -602,7 -612,7 +599,7 @@@ again
        }
        gst_adapter_push (priv->adapter_out, buf);
        priv->out_dur += GST_BUFFER_DURATION (buf);
 -      av += GST_BUFFER_SIZE (buf);
 +      av += gst_buffer_get_size (buf);
        buf = NULL;
      }
      if (priv->out_dur > dec->priv->latency)
  
    if (G_LIKELY (buf)) {
  
 -    /* decorate */
 -    gst_buffer_set_caps (buf, GST_PAD_CAPS (dec->srcpad));
 -
      if (G_UNLIKELY (priv->discont)) {
        GST_LOG_OBJECT (dec, "marking discont");
        GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
      if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
        /* duration should always be valid for raw audio */
        g_assert (GST_BUFFER_DURATION_IS_VALID (buf));
 -      dec->segment.last_stop =
 +      dec->segment.position =
            GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
      }
  
      }
  
      GST_LOG_OBJECT (dec, "pushing buffer of size %d with ts %" GST_TIME_FORMAT
 -        ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
 +        ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf),
          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
          GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
  
  }
  
  GstFlowReturn
- gst_base_audio_decoder_finish_frame (GstBaseAudioDecoder * dec, GstBuffer * buf,
+ gst_audio_decoder_finish_frame (GstAudioDecoder * dec, GstBuffer * buf,
      gint frames)
  {
-   GstBaseAudioDecoderPrivate *priv;
-   GstBaseAudioDecoderContext *ctx;
+   GstAudioDecoderPrivate *priv;
+   GstAudioDecoderContext *ctx;
    gint samples = 0;
    GstClockTime ts, next_ts;
 +  gsize size;
  
    /* subclass should know what it is producing by now */
 -  g_return_val_if_fail (buf == NULL || GST_PAD_CAPS (dec->srcpad) != NULL,
 +  g_return_val_if_fail (buf == NULL || gst_pad_has_current_caps (dec->srcpad),
        GST_FLOW_ERROR);
    /* subclass should not hand us no data */
 -  g_return_val_if_fail (buf == NULL || GST_BUFFER_SIZE (buf) > 0,
 +  g_return_val_if_fail (buf == NULL || gst_buffer_get_size (buf) > 0,
        GST_FLOW_ERROR);
    /* no dummy calls please */
    g_return_val_if_fail (frames != 0, GST_FLOW_ERROR);
  
    priv = dec->priv;
    ctx = &dec->priv->ctx;
 +  size = buf ? gst_buffer_get_size (buf) : 0;
  
    GST_LOG_OBJECT (dec, "accepting %d bytes == %d samples for %d frames",
 -      buf ? GST_BUFFER_SIZE (buf) : -1,
 -      buf ? GST_BUFFER_SIZE (buf) / ctx->info.bpf : -1, frames);
 +      buf ? size : -1, buf ? size / ctx->info.bpf : -1, frames);
  
    /* output shoud be whole number of sample frames */
    if (G_LIKELY (buf && ctx->info.bpf)) {
 -    if (GST_BUFFER_SIZE (buf) % ctx->info.bpf)
 +    if (size % ctx->info.bpf)
        goto wrong_buffer;
      /* per channel least */
 -    samples = GST_BUFFER_SIZE (buf) / ctx->info.bpf;
 +    samples = size / ctx->info.bpf;
    }
  
    /* frame and ts book-keeping */
      priv->taglist = NULL;
    }
  
 -  buf = gst_buffer_make_metadata_writable (buf);
 +  buf = gst_buffer_make_writable (buf);
    if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (priv->base_ts))) {
      GST_BUFFER_TIMESTAMP (buf) =
          priv->base_ts +
      dec->priv->error_count--;
  
  exit:
-   return gst_base_audio_decoder_output (dec, buf);
+   return gst_audio_decoder_output (dec, buf);
  
    /* ERRORS */
  wrong_buffer:
    {
      GST_ELEMENT_ERROR (dec, STREAM, ENCODE, (NULL),
 -        ("buffer size %d not a multiple of %d", GST_BUFFER_SIZE (buf),
 -            ctx->info.bpf));
 +        ("buffer size %d not a multiple of %d", size, ctx->info.bpf));
      gst_buffer_unref (buf);
      return GST_FLOW_ERROR;
    }
@@@ -823,17 -836,17 +820,17 @@@ overflow
  }
  
  static GstFlowReturn
- gst_base_audio_decoder_handle_frame (GstBaseAudioDecoder * dec,
-     GstBaseAudioDecoderClass * klass, GstBuffer * buffer)
+ gst_audio_decoder_handle_frame (GstAudioDecoder * dec,
+     GstAudioDecoderClass * klass, GstBuffer * buffer)
  {
    if (G_LIKELY (buffer)) {
 +    gsize size = gst_buffer_get_size (buffer);
      /* keep around for admin */
      GST_LOG_OBJECT (dec, "tracking frame size %d, ts %" GST_TIME_FORMAT,
 -        GST_BUFFER_SIZE (buffer),
 -        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
 +        size, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
      g_queue_push_tail (&dec->priv->frames, buffer);
      dec->priv->ctx.delay = dec->priv->frames.length;
 -    dec->priv->bytes_in += GST_BUFFER_SIZE (buffer);
 +    dec->priv->bytes_in += size;
    } else {
      GST_LOG_OBJECT (dec, "providing subclass with NULL frame");
    }
  
  /* maybe subclass configurable instead, but this allows for a whole lot of
   * raw samples, so at least quite some encoded ... */
- #define GST_BASE_AUDIO_DECODER_MAX_SYNC     10 * 8 * 2 * 1024
+ #define GST_AUDIO_DECODER_MAX_SYNC     10 * 8 * 2 * 1024
  
  static GstFlowReturn
- gst_base_audio_decoder_push_buffers (GstBaseAudioDecoder * dec, gboolean force)
+ gst_audio_decoder_push_buffers (GstAudioDecoder * dec, gboolean force)
  {
-   GstBaseAudioDecoderClass *klass;
-   GstBaseAudioDecoderPrivate *priv;
-   GstBaseAudioDecoderContext *ctx;
+   GstAudioDecoderClass *klass;
+   GstAudioDecoderPrivate *priv;
+   GstAudioDecoderContext *ctx;
    GstFlowReturn ret = GST_FLOW_OK;
    GstBuffer *buffer;
    gint av, flush;
  
-   klass = GST_BASE_AUDIO_DECODER_GET_CLASS (dec);
+   klass = GST_AUDIO_DECODER_GET_CLASS (dec);
    priv = dec->priv;
    ctx = &dec->priv->ctx;
  
            flush = offset;
            /* avoid parsing indefinitely */
            priv->sync_flush += offset;
-           if (priv->sync_flush > GST_BASE_AUDIO_DECODER_MAX_SYNC)
+           if (priv->sync_flush > GST_AUDIO_DECODER_MAX_SYNC)
              goto parse_failed;
          }
  
          priv->prev_ts = ts;
        }
        buffer = gst_adapter_take_buffer (priv->adapter, len);
 -      buffer = gst_buffer_make_metadata_writable (buffer);
 +      buffer = gst_buffer_make_writable (buffer);
        GST_BUFFER_TIMESTAMP (buffer) = ts;
        flush += len;
      } else {
        buffer = NULL;
      }
  
-     ret = gst_base_audio_decoder_handle_frame (dec, klass, buffer);
+     ret = gst_audio_decoder_handle_frame (dec, klass, buffer);
  
      /* do not keep pushing it ... */
      if (G_UNLIKELY (!av)) {
@@@ -951,7 -964,7 +948,7 @@@ parse_failed
  }
  
  static GstFlowReturn
- gst_base_audio_decoder_drain (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_drain (GstAudioDecoder * dec)
  {
    GstFlowReturn ret;
  
      /* chain eventually calls upon drain as well, but by that time
       * gather list should be clear, so ok ... */
      if (dec->segment.rate < 0.0 && dec->priv->gather)
-       gst_base_audio_decoder_chain_reverse (dec, NULL);
+       gst_audio_decoder_chain_reverse (dec, NULL);
      /* have subclass give all it can */
-     ret = gst_base_audio_decoder_push_buffers (dec, TRUE);
+     ret = gst_audio_decoder_push_buffers (dec, TRUE);
      /* ensure all output sent */
-     ret = gst_base_audio_decoder_output (dec, NULL);
+     ret = gst_audio_decoder_output (dec, NULL);
      /* everything should be away now */
      if (dec->priv->frames.length) {
        /* not fatal/impossible though if subclass/codec eats stuff */
  
  /* hard == FLUSH, otherwise discont */
  static GstFlowReturn
- gst_base_audio_decoder_flush (GstBaseAudioDecoder * dec, gboolean hard)
+ gst_audio_decoder_flush (GstAudioDecoder * dec, gboolean hard)
  {
-   GstBaseAudioDecoderClass *klass;
+   GstAudioDecoderClass *klass;
    GstFlowReturn ret = GST_FLOW_OK;
  
-   klass = GST_BASE_AUDIO_DECODER_GET_CLASS (dec);
+   klass = GST_AUDIO_DECODER_GET_CLASS (dec);
  
    GST_LOG_OBJECT (dec, "flush hard %d", hard);
  
    if (!hard) {
-     ret = gst_base_audio_decoder_drain (dec);
+     ret = gst_audio_decoder_drain (dec);
    } else {
-     gst_base_audio_decoder_clear_queues (dec);
+     gst_audio_decoder_clear_queues (dec);
      gst_segment_init (&dec->segment, GST_FORMAT_TIME);
      dec->priv->error_count = 0;
    }
    if (klass->flush && dec->priv->samples_out > 0)
      klass->flush (dec, hard);
    /* and get (re)set for the sequel */
-   gst_base_audio_decoder_reset (dec, FALSE);
+   gst_audio_decoder_reset (dec, FALSE);
  
    return ret;
  }
  
  static GstFlowReturn
- gst_base_audio_decoder_chain_forward (GstBaseAudioDecoder * dec,
-     GstBuffer * buffer)
+ gst_audio_decoder_chain_forward (GstAudioDecoder * dec, GstBuffer * buffer)
  {
    GstFlowReturn ret;
  
    dec->priv->drained = FALSE;
  
    /* hand to subclass */
-   ret = gst_base_audio_decoder_push_buffers (dec, FALSE);
+   ret = gst_audio_decoder_push_buffers (dec, FALSE);
  
    GST_LOG_OBJECT (dec, "chain-done");
    return ret;
  }
  
  static void
- gst_base_audio_decoder_clear_queues (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_clear_queues (GstAudioDecoder * dec)
  {
-   GstBaseAudioDecoderPrivate *priv = dec->priv;
+   GstAudioDecoderPrivate *priv = dec->priv;
  
    g_list_foreach (priv->queued, (GFunc) gst_mini_object_unref, NULL);
    g_list_free (priv->queued);
   * Etc..
   */
  static GstFlowReturn
- gst_base_audio_decoder_flush_decode (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_flush_decode (GstAudioDecoder * dec)
  {
-   GstBaseAudioDecoderPrivate *priv = dec->priv;
+   GstAudioDecoderPrivate *priv = dec->priv;
    GstFlowReturn res = GST_FLOW_OK;
    GList *walk;
  
    GST_DEBUG_OBJECT (dec, "flushing buffers to decoder");
  
    /* clear buffer and decoder state */
-   gst_base_audio_decoder_flush (dec, FALSE);
+   gst_audio_decoder_flush (dec, FALSE);
  
    while (walk) {
      GList *next;
      next = g_list_next (walk);
      /* decode buffer, resulting data prepended to output queue */
      gst_buffer_ref (buf);
-     res = gst_base_audio_decoder_chain_forward (dec, buf);
+     res = gst_audio_decoder_chain_forward (dec, buf);
  
      /* if we generated output, we can discard the buffer, else we
       * keep it in the queue */
    }
  
    /* drain any aggregation (or otherwise) leftover */
-   gst_base_audio_decoder_drain (dec);
+   gst_audio_decoder_drain (dec);
  
    /* now send queued data downstream */
    while (priv->queued) {
      if (G_LIKELY (res == GST_FLOW_OK)) {
        GST_DEBUG_OBJECT (dec, "pushing buffer %p of size %u, "
            "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
 -          GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
 +          gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
            GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
        /* should be already, but let's be sure */
 -      buf = gst_buffer_make_metadata_writable (buf);
 +      buf = gst_buffer_make_writable (buf);
        /* avoid stray DISCONT from forward processing,
         * which have no meaning in reverse pushing */
        GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
  }
  
  static GstFlowReturn
- gst_base_audio_decoder_chain_reverse (GstBaseAudioDecoder * dec,
-     GstBuffer * buf)
+ gst_audio_decoder_chain_reverse (GstAudioDecoder * dec, GstBuffer * buf)
  {
-   GstBaseAudioDecoderPrivate *priv = dec->priv;
+   GstAudioDecoderPrivate *priv = dec->priv;
    GstFlowReturn result = GST_FLOW_OK;
  
    /* if we have a discont, move buffers to the decode list */
        priv->decode = g_list_prepend (priv->decode, gbuf);
      }
      /* decode stuff in the decode queue */
-     gst_base_audio_decoder_flush_decode (dec);
+     gst_audio_decoder_flush_decode (dec);
    }
  
    if (G_LIKELY (buf)) {
      GST_DEBUG_OBJECT (dec, "gathering buffer %p of size %u, "
          "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
 -        GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
 +        gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
          GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
  
      /* add buffer to gather queue */
  }
  
  static GstFlowReturn
- gst_base_audio_decoder_chain (GstPad * pad, GstBuffer * buffer)
+ gst_audio_decoder_chain (GstPad * pad, GstBuffer * buffer)
  {
-   GstBaseAudioDecoder *dec;
+   GstAudioDecoder *dec;
    GstFlowReturn ret;
  
-   dec = GST_BASE_AUDIO_DECODER (GST_PAD_PARENT (pad));
+   dec = GST_AUDIO_DECODER (GST_PAD_PARENT (pad));
  
    GST_LOG_OBJECT (dec,
        "received buffer of size %d with ts %" GST_TIME_FORMAT
 -      ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer),
 +      ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buffer),
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
  
      samples = dec->priv->samples;
  
      GST_DEBUG_OBJECT (dec, "handling discont");
-     gst_base_audio_decoder_flush (dec, FALSE);
+     gst_audio_decoder_flush (dec, FALSE);
      dec->priv->discont = TRUE;
  
      /* buffer may claim DISCONT loudly, if it can't tell us where we are now,
    }
  
    if (dec->segment.rate > 0.0)
-     ret = gst_base_audio_decoder_chain_forward (dec, buffer);
+     ret = gst_audio_decoder_chain_forward (dec, buffer);
    else
-     ret = gst_base_audio_decoder_chain_reverse (dec, buffer);
+     ret = gst_audio_decoder_chain_reverse (dec, buffer);
  
    return ret;
  }
  /* perform upstream byte <-> time conversion (duration, seeking)
   * if subclass allows and if enough data for moderately decent conversion */
  static inline gboolean
- gst_base_audio_decoder_do_byte (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_do_byte (GstAudioDecoder * dec)
  {
    return dec->priv->ctx.do_byte_time && dec->priv->ctx.info.bpf &&
        dec->priv->ctx.info.rate <= dec->priv->samples_out;
  }
  
  static gboolean
- gst_base_audio_decoder_sink_eventfunc (GstBaseAudioDecoder * dec,
-     GstEvent * event)
+ gst_audio_decoder_sink_eventfunc (GstAudioDecoder * dec, GstEvent * event)
  {
    gboolean handled = FALSE;
  
    switch (GST_EVENT_TYPE (event)) {
 -    case GST_EVENT_NEWSEGMENT:
 +    case GST_EVENT_SEGMENT:
      {
 -      GstFormat format;
 -      gdouble rate, arate;
 -      gint64 start, stop, time;
 -      gboolean update;
 +      GstSegment seg;
  
 -      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
 -          &start, &stop, &time);
 +      gst_event_copy_segment (event, &seg);
  
 -      if (format == GST_FORMAT_TIME) {
 -        GST_DEBUG_OBJECT (dec, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
 -            " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
 -            ", rate %g, applied_rate %g",
 -            GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time),
 -            rate, arate);
 +      if (seg.format == GST_FORMAT_TIME) {
 +        GST_DEBUG_OBJECT (dec, "received TIME SEGMENT %" GST_PTR_FORMAT, &seg);
        } else {
 -        GstFormat dformat = GST_FORMAT_TIME;
 -
 -        GST_DEBUG_OBJECT (dec, "received NEW_SEGMENT %" G_GINT64_FORMAT
 -            " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
 -            ", rate %g, applied_rate %g", start, stop, time, rate, arate);
 +        gint64 nstart;
 +        GST_DEBUG_OBJECT (dec, "received SEGMENT %" GST_PTR_FORMAT, &seg);
          /* handle newsegment resulting from legacy simple seeking */
          /* note that we need to convert this whether or not enough data
           * to handle initial newsegment */
          if (dec->priv->ctx.do_byte_time &&
 -            gst_pad_query_convert (dec->sinkpad, GST_FORMAT_BYTES, start,
 -                &dformat, &start)) {
 +            gst_pad_query_convert (dec->sinkpad, GST_FORMAT_BYTES, seg.start,
 +                GST_FORMAT_TIME, &nstart)) {
            /* best attempt convert */
            /* as these are only estimates, stop is kept open-ended to avoid
             * premature cutting */
            GST_DEBUG_OBJECT (dec, "converted to TIME start %" GST_TIME_FORMAT,
 -              GST_TIME_ARGS (start));
 -          format = GST_FORMAT_TIME;
 -          time = start;
 -          stop = GST_CLOCK_TIME_NONE;
 +              GST_TIME_ARGS (nstart));
 +          seg.format = GST_FORMAT_TIME;
 +          seg.start = nstart;
 +          seg.time = nstart;
 +          seg.stop = GST_CLOCK_TIME_NONE;
            /* replace event */
            gst_event_unref (event);
 -          event = gst_event_new_new_segment_full (update, rate, arate,
 -              GST_FORMAT_TIME, start, stop, time);
 +          event = gst_event_new_segment (&seg);
          } else {
            GST_DEBUG_OBJECT (dec, "unsupported format; ignoring");
            break;
        }
  
        /* finish current segment */
-       gst_base_audio_decoder_drain (dec);
+       gst_audio_decoder_drain (dec);
  
 +#if 0
        if (update) {
          /* time progressed without data, see if we can fill the gap with
           * some concealment data */
          GST_DEBUG_OBJECT (dec,
 -            "segment update: plc %d, do_plc %d, last_stop %" GST_TIME_FORMAT,
 +            "segment update: plc %d, do_plc %d, position %" GST_TIME_FORMAT,
              dec->priv->plc, dec->priv->ctx.do_plc,
 -            GST_TIME_ARGS (dec->segment.last_stop));
 +            GST_TIME_ARGS (dec->segment.position));
          if (dec->priv->plc && dec->priv->ctx.do_plc &&
 -            dec->segment.rate > 0.0 && dec->segment.last_stop < start) {
 +            dec->segment.rate > 0.0 && dec->segment.position < start) {
-           GstBaseAudioDecoderClass *klass;
+           GstAudioDecoderClass *klass;
            GstBuffer *buf;
  
-           klass = GST_BASE_AUDIO_DECODER_GET_CLASS (dec);
+           klass = GST_AUDIO_DECODER_GET_CLASS (dec);
            /* hand subclass empty frame with duration that needs covering */
            buf = gst_buffer_new ();
 -          GST_BUFFER_DURATION (buf) = start - dec->segment.last_stop;
 +          GST_BUFFER_DURATION (buf) = start - dec->segment.position;
            /* best effort, not much error handling */
-           gst_base_audio_decoder_handle_frame (dec, klass, buf);
+           gst_audio_decoder_handle_frame (dec, klass, buf);
          }
 -      } else {
 +      } else
 +#endif
 +      {
          /* prepare for next one */
-         gst_base_audio_decoder_flush (dec, FALSE);
+         gst_audio_decoder_flush (dec, FALSE);
          /* and that's where we time from,
           * in case upstream does not come up with anything better
           * (e.g. upstream BYTE) */
 -        if (format != GST_FORMAT_TIME) {
 -          dec->priv->base_ts = start;
 +        if (seg.format != GST_FORMAT_TIME) {
 +          dec->priv->base_ts = seg.start;
            dec->priv->samples = 0;
          }
        }
  
        /* and follow along with segment */
 -      gst_segment_set_newsegment_full (&dec->segment, update, rate, arate,
 -          format, start, stop, time);
 -
 +      dec->segment = seg;
        gst_pad_push_event (dec->srcpad, event);
        handled = TRUE;
        break;
  
      case GST_EVENT_FLUSH_STOP:
        /* prepare for fresh start */
-       gst_base_audio_decoder_flush (dec, TRUE);
+       gst_audio_decoder_flush (dec, TRUE);
        break;
  
      case GST_EVENT_EOS:
-       gst_base_audio_decoder_drain (dec);
+       gst_audio_decoder_drain (dec);
        break;
  
-       gst_base_audio_decoder_sink_setcaps (dec, caps);
 +    case GST_EVENT_CAPS:
 +    {
 +      GstCaps *caps;
 +
 +      gst_event_parse_caps (event, &caps);
++      gst_audio_decoder_sink_setcaps (dec, caps);
 +      gst_event_unref (event);
 +      handled = TRUE;
 +      break;
 +    }
      default:
        break;
    }
  }
  
  static gboolean
- gst_base_audio_decoder_sink_event (GstPad * pad, GstEvent * event)
+ gst_audio_decoder_sink_event (GstPad * pad, GstEvent * event)
  {
-   GstBaseAudioDecoder *dec;
-   GstBaseAudioDecoderClass *klass;
+   GstAudioDecoder *dec;
+   GstAudioDecoderClass *klass;
    gboolean handled = FALSE;
    gboolean ret = TRUE;
  
-   dec = GST_BASE_AUDIO_DECODER (gst_pad_get_parent (pad));
-   klass = GST_BASE_AUDIO_DECODER_GET_CLASS (dec);
+   dec = GST_AUDIO_DECODER (gst_pad_get_parent (pad));
+   klass = GST_AUDIO_DECODER_GET_CLASS (dec);
  
    GST_DEBUG_OBJECT (dec, "received event %d, %s", GST_EVENT_TYPE (event),
        GST_EVENT_TYPE_NAME (event));
      handled = klass->event (dec, event);
  
    if (!handled)
-     handled = gst_base_audio_decoder_sink_eventfunc (dec, event);
+     handled = gst_audio_decoder_sink_eventfunc (dec, event);
  
    if (!handled)
      ret = gst_pad_event_default (pad, event);
  }
  
  static gboolean
- gst_base_audio_decoder_do_seek (GstBaseAudioDecoder * dec, GstEvent * event)
+ gst_audio_decoder_do_seek (GstAudioDecoder * dec, GstEvent * event)
  {
    GstSeekFlags flags;
    GstSeekType start_type, end_type;
    }
  
    memcpy (&seek_segment, &dec->segment, sizeof (seek_segment));
 -  gst_segment_set_seek (&seek_segment, rate, format, flags, start_type,
 +  gst_segment_do_seek (&seek_segment, rate, format, flags, start_type,
        start_time, end_type, end_time, NULL);
 -  start_time = seek_segment.last_stop;
 +  start_time = seek_segment.position;
  
 -  format = GST_FORMAT_BYTES;
    if (!gst_pad_query_convert (dec->sinkpad, GST_FORMAT_TIME, start_time,
 -          &format, &start)) {
 +          GST_FORMAT_BYTES, &start)) {
      GST_DEBUG_OBJECT (dec, "conversion failed");
      return FALSE;
    }
  }
  
  static gboolean
- gst_base_audio_decoder_src_event (GstPad * pad, GstEvent * event)
+ gst_audio_decoder_src_event (GstPad * pad, GstEvent * event)
  {
-   GstBaseAudioDecoder *dec;
+   GstAudioDecoder *dec;
    gboolean res = FALSE;
  
-   dec = GST_BASE_AUDIO_DECODER (gst_pad_get_parent (pad));
+   dec = GST_AUDIO_DECODER (gst_pad_get_parent (pad));
  
    GST_DEBUG_OBJECT (dec, "received event %d, %s", GST_EVENT_TYPE (event),
        GST_EVENT_TYPE_NAME (event));
    switch (GST_EVENT_TYPE (event)) {
      case GST_EVENT_SEEK:
      {
 -      GstFormat format, tformat;
 +      GstFormat format;
        gdouble rate;
        GstSeekFlags flags;
        GstSeekType cur_type, stop_type;
  
        /* if upstream fails for a time seek, maybe we can help if allowed */
        if (format == GST_FORMAT_TIME) {
-         if (gst_base_audio_decoder_do_byte (dec))
-           res = gst_base_audio_decoder_do_seek (dec, event);
+         if (gst_audio_decoder_do_byte (dec))
+           res = gst_audio_decoder_do_seek (dec, event);
          break;
        }
  
        /* ... though a non-time seek can be aided as well */
        /* First bring the requested format to time */
 -      tformat = GST_FORMAT_TIME;
 -      if (!(res = gst_pad_query_convert (pad, format, cur, &tformat, &tcur)))
 +      if (!(res =
 +              gst_pad_query_convert (pad, format, cur, GST_FORMAT_TIME, &tcur)))
          goto convert_error;
 -      if (!(res = gst_pad_query_convert (pad, format, stop, &tformat, &tstop)))
 +      if (!(res =
 +              gst_pad_query_convert (pad, format, stop, GST_FORMAT_TIME,
 +                  &tstop)))
          goto convert_error;
  
        /* then seek with time on the peer */
@@@ -1537,7 -1546,7 +1531,7 @@@ convert_error
  }
  
  /*
-  * gst_base_audio_encoded_audio_convert:
+  * gst_audio_encoded_audio_convert:
   * @fmt: audio format of the encoded audio
   * @bytes: number of encoded bytes
   * @samples: number of encoded samples
   * BYTE and TIME format by using estimated bitrate based on
   * @samples and @bytes (and @fmt).
   */
- /* FIXME: make gst_base_audio_encoded_audio_convert() public? */
+ /* FIXME: make gst_audio_encoded_audio_convert() public? */
  static gboolean
- gst_base_audio_encoded_audio_convert (GstAudioInfo * fmt,
+ gst_audio_encoded_audio_convert (GstAudioInfo * fmt,
      gint64 bytes, gint64 samples, GstFormat src_format,
      gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
  {
@@@ -1608,12 -1617,12 +1602,12 @@@ exit
  }
  
  static gboolean
- gst_base_audio_decoder_sink_query (GstPad * pad, GstQuery * query)
+ gst_audio_decoder_sink_query (GstPad * pad, GstQuery * query)
  {
    gboolean res = TRUE;
-   GstBaseAudioDecoder *dec;
+   GstAudioDecoder *dec;
  
-   dec = GST_BASE_AUDIO_DECODER (gst_pad_get_parent (pad));
+   dec = GST_AUDIO_DECODER (gst_pad_get_parent (pad));
  
    switch (GST_QUERY_TYPE (query)) {
      case GST_QUERY_FORMATS:
        gint64 src_val, dest_val;
  
        gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
-       if (!(res = gst_base_audio_encoded_audio_convert (&dec->priv->ctx.info,
+       if (!(res = gst_audio_encoded_audio_convert (&dec->priv->ctx.info,
                    dec->priv->bytes_in, dec->priv->samples_out,
                    src_fmt, src_val, &dest_fmt, &dest_val)))
          goto error;
@@@ -1646,9 -1655,9 +1640,9 @@@ error
  }
  
  static const GstQueryType *
- gst_base_audio_decoder_get_query_types (GstPad * pad)
+ gst_audio_decoder_get_query_types (GstPad * pad)
  {
-   static const GstQueryType gst_base_audio_decoder_src_query_types[] = {
+   static const GstQueryType gst_audio_decoder_src_query_types[] = {
      GST_QUERY_POSITION,
      GST_QUERY_DURATION,
      GST_QUERY_CONVERT,
      0
    };
  
-   return gst_base_audio_decoder_src_query_types;
+   return gst_audio_decoder_src_query_types;
  }
  
  /* FIXME ? are any of these queries (other than latency) a decoder's business ??
   * segment stuff etc at all
   * Supposedly that's backward compatibility ... */
  static gboolean
- gst_base_audio_decoder_src_query (GstPad * pad, GstQuery * query)
+ gst_audio_decoder_src_query (GstPad * pad, GstQuery * query)
  {
-   GstBaseAudioDecoder *dec;
+   GstAudioDecoder *dec;
    GstPad *peerpad;
    gboolean res = FALSE;
  
-   dec = GST_BASE_AUDIO_DECODER (GST_PAD_PARENT (pad));
+   dec = GST_AUDIO_DECODER (GST_PAD_PARENT (pad));
    peerpad = gst_pad_get_peer (GST_PAD (dec->sinkpad));
  
    GST_LOG_OBJECT (dec, "handling query: %" GST_PTR_FORMAT, query);
  
        gst_query_parse_duration (query, &format, NULL);
        /* try answering TIME by converting from BYTE if subclass allows  */
-       if (format == GST_FORMAT_TIME && gst_base_audio_decoder_do_byte (dec)) {
+       if (format == GST_FORMAT_TIME && gst_audio_decoder_do_byte (dec)) {
          gint64 value;
  
 -        format = GST_FORMAT_BYTES;
 -        if (gst_pad_query_peer_duration (dec->sinkpad, &format, &value)) {
 +        if (gst_pad_query_peer_duration (dec->sinkpad, GST_FORMAT_BYTES,
 +                &value)) {
            GST_LOG_OBJECT (dec, "upstream size %" G_GINT64_FORMAT, value);
 -          format = GST_FORMAT_TIME;
            if (gst_pad_query_convert (dec->sinkpad, GST_FORMAT_BYTES, value,
 -                  &format, &value)) {
 +                  GST_FORMAT_TIME, &value)) {
              gst_query_set_duration (query, GST_FORMAT_TIME, value);
              res = TRUE;
            }
        }
  
        /* we start from the last seen time */
 -      time = dec->segment.last_stop;
 +      time = dec->segment.position;
        /* correct for the segment values */
        time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
  
        /* and convert to the final format */
        gst_query_parse_position (query, &format, NULL);
        if (!(res = gst_pad_query_convert (pad, GST_FORMAT_TIME, time,
 -                  &format, &value)))
 +                  format, &value)))
          break;
  
        gst_query_set_position (query, format, value);
  }
  
  static gboolean
- gst_base_audio_decoder_stop (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_stop (GstAudioDecoder * dec)
  {
-   GstBaseAudioDecoderClass *klass;
+   GstAudioDecoderClass *klass;
    gboolean ret = TRUE;
  
-   GST_DEBUG_OBJECT (dec, "gst_base_audio_decoder_stop");
+   GST_DEBUG_OBJECT (dec, "gst_audio_decoder_stop");
  
-   klass = GST_BASE_AUDIO_DECODER_GET_CLASS (dec);
+   klass = GST_AUDIO_DECODER_GET_CLASS (dec);
  
    if (klass->stop) {
      ret = klass->stop (dec);
    }
  
    /* clean up */
-   gst_base_audio_decoder_reset (dec, TRUE);
+   gst_audio_decoder_reset (dec, TRUE);
  
    if (ret)
      dec->priv->active = FALSE;
  }
  
  static gboolean
- gst_base_audio_decoder_start (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_start (GstAudioDecoder * dec)
  {
-   GstBaseAudioDecoderClass *klass;
+   GstAudioDecoderClass *klass;
    gboolean ret = TRUE;
  
-   GST_DEBUG_OBJECT (dec, "gst_base_audio_decoder_start");
+   GST_DEBUG_OBJECT (dec, "gst_audio_decoder_start");
  
-   klass = GST_BASE_AUDIO_DECODER_GET_CLASS (dec);
+   klass = GST_AUDIO_DECODER_GET_CLASS (dec);
  
    /* arrange clean state */
-   gst_base_audio_decoder_reset (dec, TRUE);
+   gst_audio_decoder_reset (dec, TRUE);
  
    if (klass->start) {
      ret = klass->start (dec);
  }
  
  static void
- gst_base_audio_decoder_get_property (GObject * object, guint prop_id,
+ gst_audio_decoder_get_property (GObject * object, guint prop_id,
      GValue * value, GParamSpec * pspec)
  {
-   GstBaseAudioDecoder *dec;
+   GstAudioDecoder *dec;
  
-   dec = GST_BASE_AUDIO_DECODER (object);
+   dec = GST_AUDIO_DECODER (object);
  
    switch (prop_id) {
      case PROP_LATENCY:
  }
  
  static void
- gst_base_audio_decoder_set_property (GObject * object, guint prop_id,
+ gst_audio_decoder_set_property (GObject * object, guint prop_id,
      const GValue * value, GParamSpec * pspec)
  {
-   GstBaseAudioDecoder *dec;
+   GstAudioDecoder *dec;
  
-   dec = GST_BASE_AUDIO_DECODER (object);
+   dec = GST_AUDIO_DECODER (object);
  
    switch (prop_id) {
      case PROP_LATENCY:
  }
  
  static GstStateChangeReturn
- gst_base_audio_decoder_change_state (GstElement * element,
-     GstStateChange transition)
+ gst_audio_decoder_change_state (GstElement * element, GstStateChange transition)
  {
-   GstBaseAudioDecoder *codec;
+   GstAudioDecoder *codec;
    GstStateChangeReturn ret;
  
-   codec = GST_BASE_AUDIO_DECODER (element);
+   codec = GST_AUDIO_DECODER (element);
  
    switch (transition) {
      case GST_STATE_CHANGE_NULL_TO_READY:
        break;
      case GST_STATE_CHANGE_READY_TO_PAUSED:
-       if (!gst_base_audio_decoder_start (codec)) {
+       if (!gst_audio_decoder_start (codec)) {
          goto start_failed;
        }
        break;
        break;
    }
  
 -  ret = parent_class->change_state (element, transition);
 +  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  
    switch (transition) {
      case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
        break;
      case GST_STATE_CHANGE_PAUSED_TO_READY:
-       if (!gst_base_audio_decoder_stop (codec)) {
+       if (!gst_audio_decoder_stop (codec)) {
          goto stop_failed;
        }
        break;
@@@ -1931,7 -1940,7 +1924,7 @@@ stop_failed
  }
  
  GstFlowReturn
- _gst_base_audio_decoder_error (GstBaseAudioDecoder * dec, gint weight,
+ _gst_audio_decoder_error (GstAudioDecoder * dec, gint weight,
      GQuark domain, gint code, gchar * txt, gchar * dbg, const gchar * file,
      const gchar * function, gint line)
  {
  }
  
  /**
-  * gst_base_audio_decoder_get_audio_info:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_get_audio_info:
+  * @dec: a #GstAudioDecoder
   *
   * Returns: a #GstAudioInfo describing the input audio format
   *
   * Since: 0.10.36
   */
  GstAudioInfo *
- gst_base_audio_decoder_get_audio_info (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_get_audio_info (GstAudioDecoder * dec)
  {
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_DECODER (dec), NULL);
+   g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), NULL);
  
    return &dec->priv->ctx.info;
  }
  
  /**
-  * gst_base_audio_decoder_set_plc_aware:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_set_plc_aware:
+  * @dec: a #GstAudioDecoder
   * @plc: new plc state
   *
   * Indicates whether or not subclass handles packet loss concealment (plc).
   * Since: 0.10.36
   */
  void
- gst_base_audio_decoder_set_plc_aware (GstBaseAudioDecoder * dec, gboolean plc)
+ gst_audio_decoder_set_plc_aware (GstAudioDecoder * dec, gboolean plc)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (dec));
+   g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
  
    dec->priv->ctx.do_plc = plc;
  }
  
  /**
-  * gst_base_audio_decoder_get_plc_aware:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_get_plc_aware:
+  * @dec: a #GstAudioDecoder
   *
   * Returns: currently configured plc handling
   *
   * Since: 0.10.36
   */
  gint
- gst_base_audio_decoder_get_plc_aware (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_get_plc_aware (GstAudioDecoder * dec)
  {
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_DECODER (dec), 0);
+   g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
  
    return dec->priv->ctx.do_plc;
  }
  
  /**
-  * gst_base_audio_decoder_set_byte_time:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_set_byte_time:
+  * @dec: a #GstAudioDecoder
   * @enabled: whether to enable byte to time conversion
   *
   * Allows baseclass to perform byte to time estimated conversion.
   * Since: 0.10.36
   */
  void
- gst_base_audio_decoder_set_byte_time (GstBaseAudioDecoder * dec,
-     gboolean enabled)
+ gst_audio_decoder_set_byte_time (GstAudioDecoder * dec, gboolean enabled)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (dec));
+   g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
  
    dec->priv->ctx.do_byte_time = enabled;
  }
  
  /**
-  * gst_base_audio_decoder_get_byte_time:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_get_byte_time:
+  * @dec: a #GstAudioDecoder
   *
   * Returns: currently configured byte to time conversion setting
   *
   * Since: 0.10.36
   */
  gint
- gst_base_audio_decoder_get_byte_time (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_get_byte_time (GstAudioDecoder * dec)
  {
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_DECODER (dec), 0);
+   g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
  
    return dec->priv->ctx.do_byte_time;
  }
  
  /**
-  * gst_base_audio_decoder_get_delay:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_get_delay:
+  * @dec: a #GstAudioDecoder
   *
   * Returns: currently configured decoder delay
   *
   * Since: 0.10.36
   */
  gint
- gst_base_audio_decoder_get_delay (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_get_delay (GstAudioDecoder * dec)
  {
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_DECODER (dec), 0);
+   g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
  
    return dec->priv->ctx.delay;
  }
  
  /**
-  * gst_base_audio_decoder_set_max_errors:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_set_max_errors:
+  * @dec: a #GstAudioDecoder
   * @num: max tolerated errors
   *
   * Sets numbers of tolerated decoder errors, where a tolerated one is then only
   * Since: 0.10.36
   */
  void
- gst_base_audio_decoder_set_max_errors (GstBaseAudioDecoder * enc, gint num)
+ gst_audio_decoder_set_max_errors (GstAudioDecoder * dec, gint num)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
  
-   enc->priv->ctx.max_errors = num;
+   dec->priv->ctx.max_errors = num;
  }
  
  /**
-  * gst_base_audio_decoder_get_max_errors:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_get_max_errors:
+  * @dec: a #GstAudioDecoder
   *
   * Returns: currently configured decoder tolerated error count.
   *
   * Since: 0.10.36
   */
  gint
- gst_base_audio_decoder_get_max_errors (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_get_max_errors (GstAudioDecoder * dec)
  {
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_DECODER (dec), 0);
+   g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
  
    return dec->priv->ctx.max_errors;
  }
  
  /**
-  * gst_base_audio_decoder_set_latency:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_set_latency:
+  * @dec: a #GstAudioDecoder
   * @min: minimum latency
   * @max: maximum latency
   *
   * Since: 0.10.36
   */
  void
- gst_base_audio_decoder_set_latency (GstBaseAudioDecoder * dec,
+ gst_audio_decoder_set_latency (GstAudioDecoder * dec,
      GstClockTime min, GstClockTime max)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (dec));
+   g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
  
    GST_OBJECT_LOCK (dec);
    dec->priv->ctx.min_latency = min;
  }
  
  /**
-  * gst_base_audio_decoder_get_latency:
-  * @dec: a #GstBaseAudioDecoder
-  * @min: a pointer to storage to hold minimum latency
-  * @max: a pointer to storage to hold maximum latency
+  * gst_audio_decoder_get_latency:
+  * @dec: a #GstAudioDecoder
+  * @min: (out) (allow-none): a pointer to storage to hold minimum latency
+  * @max: (out) (allow-none): a pointer to storage to hold maximum latency
   *
-  * Returns currently configured latency.
+  * Sets the variables pointed to by @min and @max to the currently configured
+  * latency.
   *
   * Since: 0.10.36
   */
  void
- gst_base_audio_decoder_get_latency (GstBaseAudioDecoder * dec,
+ gst_audio_decoder_get_latency (GstAudioDecoder * dec,
      GstClockTime * min, GstClockTime * max)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (dec));
+   g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
  
    GST_OBJECT_LOCK (dec);
    if (min)
  }
  
  /**
-  * gst_base_audio_decoder_get_parse_state:
-  * @dec: a #GstBaseAudioDecoder
-  * @min: a pointer to storage to hold current sync state
-  * @max: a pointer to storage to hold current eos state
+  * gst_audio_decoder_get_parse_state:
+  * @dec: a #GstAudioDecoder
+  * @sync: a pointer to a variable to hold the current sync state
+  * @eos: a pointer to a variable to hold the current eos state
   *
   * Return current parsing (sync and eos) state.
   *
   * Since: 0.10.36
   */
  void
- gst_base_audio_decoder_get_parse_state (GstBaseAudioDecoder * dec,
+ gst_audio_decoder_get_parse_state (GstAudioDecoder * dec,
      gboolean * sync, gboolean * eos)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (dec));
+   g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
  
    if (sync)
      *sync = dec->priv->ctx.sync;
  }
  
  /**
-  * gst_base_audio_decoder_set_plc:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_set_plc:
+  * @dec: a #GstAudioDecoder
   * @enabled: new state
   *
   * Enable or disable decoder packet loss concealment, provided subclass
   * Since: 0.10.36
   */
  void
- gst_base_audio_decoder_set_plc (GstBaseAudioDecoder * dec, gboolean enabled)
+ gst_audio_decoder_set_plc (GstAudioDecoder * dec, gboolean enabled)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (dec));
+   g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
  
    GST_LOG_OBJECT (dec, "enabled: %d", enabled);
  
  }
  
  /**
-  * gst_base_audio_decoder_get_plc:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_get_plc:
+  * @dec: a #GstAudioDecoder
   *
   * Queries decoder packet loss concealment handling.
   *
   * Since: 0.10.36
   */
  gboolean
- gst_base_audio_decoder_get_plc (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_get_plc (GstAudioDecoder * dec)
  {
    gboolean result;
  
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_DECODER (dec), FALSE);
+   g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), FALSE);
  
    GST_OBJECT_LOCK (dec);
    result = dec->priv->plc;
  }
  
  /**
-  * gst_base_audio_decoder_set_min_latency:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_set_min_latency:
+  * @dec: a #GstAudioDecoder
   * @num: new minimum latency
   *
   * Sets decoder minimum aggregation latency.
   * Since: 0.10.36
   */
  void
- gst_base_audio_decoder_set_min_latency (GstBaseAudioDecoder * dec, gint64 num)
+ gst_audio_decoder_set_min_latency (GstAudioDecoder * dec, gint64 num)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (dec));
+   g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
  
    GST_OBJECT_LOCK (dec);
    dec->priv->latency = num;
  }
  
  /**
-  * gst_base_audio_decoder_get_min_latency:
-  * @enc: a #GstBaseAudioDecoder
+  * gst_audio_decoder_get_min_latency:
+  * @dec: a #GstAudioDecoder
   *
   * Queries decoder's latency aggregation.
   *
   * Since: 0.10.36
   */
  gint64
- gst_base_audio_decoder_get_min_latency (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_get_min_latency (GstAudioDecoder * dec)
  {
    gint64 result;
  
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_DECODER (dec), FALSE);
+   g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), FALSE);
  
    GST_OBJECT_LOCK (dec);
    result = dec->priv->latency;
  }
  
  /**
-  * gst_base_audio_decoder_set_tolerance:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_set_tolerance:
+  * @dec: a #GstAudioDecoder
   * @tolerance: new tolerance
   *
   * Configures decoder audio jitter tolerance threshold.
   * Since: 0.10.36
   */
  void
- gst_base_audio_decoder_set_tolerance (GstBaseAudioDecoder * dec,
-     gint64 tolerance)
+ gst_audio_decoder_set_tolerance (GstAudioDecoder * dec, gint64 tolerance)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_DECODER (dec));
+   g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
  
    GST_OBJECT_LOCK (dec);
    dec->priv->tolerance = tolerance;
  }
  
  /**
-  * gst_base_audio_decoder_get_tolerance:
-  * @dec: a #GstBaseAudioDecoder
+  * gst_audio_decoder_get_tolerance:
+  * @dec: a #GstAudioDecoder
   *
   * Queries current audio jitter tolerance threshold.
   *
   * Since: 0.10.36
   */
  gint64
- gst_base_audio_decoder_get_tolerance (GstBaseAudioDecoder * dec)
+ gst_audio_decoder_get_tolerance (GstAudioDecoder * dec)
  {
    gint64 result;
  
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_DECODER (dec), 0);
+   g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
  
    GST_OBJECT_LOCK (dec);
    result = dec->priv->tolerance;
   * Boston, MA 02111-1307, USA.
   */
  
- #ifndef _GST_BASE_AUDIO_DECODER_H_
- #define _GST_BASE_AUDIO_DECODER_H_
+ #ifndef _GST_AUDIO_DECODER_H_
+ #define _GST_AUDIO_DECODER_H_
  
  #ifndef GST_USE_UNSTABLE_API
- #warning "GstBaseAudioDecoder is unstable API and may change in future."
+ #warning "GstAudioDecoder is unstable API and may change in future."
  #warning "You can define GST_USE_UNSTABLE_API to avoid this warning."
  #endif
  
  
  G_BEGIN_DECLS
  
- #define GST_TYPE_BASE_AUDIO_DECODER \
-   (gst_base_audio_decoder_get_type())
- #define GST_BASE_AUDIO_DECODER(obj) \
-   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_AUDIO_DECODER,GstBaseAudioDecoder))
- #define GST_BASE_AUDIO_DECODER_CLASS(klass) \
-   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_AUDIO_DECODER,GstBaseAudioDecoderClass))
- #define GST_BASE_AUDIO_DECODER_GET_CLASS(obj) \
-   (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_BASE_AUDIO_DECODER,GstBaseAudioDecoderClass))
- #define GST_IS_BASE_AUDIO_DECODER(obj) \
-   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_AUDIO_DECODER))
- #define GST_IS_BASE_AUDIO_DECODER_CLASS(obj) \
-   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_AUDIO_DECODER))
+ #define GST_TYPE_AUDIO_DECODER \
+   (gst_audio_decoder_get_type())
+ #define GST_AUDIO_DECODER(obj) \
+   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_DECODER,GstAudioDecoder))
+ #define GST_AUDIO_DECODER_CLASS(klass) \
+   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_DECODER,GstAudioDecoderClass))
+ #define GST_AUDIO_DECODER_GET_CLASS(obj) \
+   (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_AUDIO_DECODER,GstAudioDecoderClass))
+ #define GST_IS_AUDIO_DECODER(obj) \
+   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_DECODER))
+ #define GST_IS_AUDIO_DECODER_CLASS(obj) \
+   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_DECODER))
  
  /**
-  * GST_BASE_AUDIO_DECODER_SINK_NAME:
+  * GST_AUDIO_DECODER_SINK_NAME:
   *
   * The name of the templates for the sink pad.
   *
   * Since: 0.10.36
   */
- #define GST_BASE_AUDIO_DECODER_SINK_NAME    "sink"
+ #define GST_AUDIO_DECODER_SINK_NAME    "sink"
  /**
-  * GST_BASE_AUDIO_DECODER_SRC_NAME:
+  * GST_AUDIO_DECODER_SRC_NAME:
   *
   * The name of the templates for the source pad.
   *
   * Since: 0.10.36
   */
- #define GST_BASE_AUDIO_DECODER_SRC_NAME     "src"
+ #define GST_AUDIO_DECODER_SRC_NAME     "src"
  
  /**
-  * GST_BASE_AUDIO_DECODER_SRC_PAD:
+  * GST_AUDIO_DECODER_SRC_PAD:
   * @obj: base audio codec instance
   *
   * Gives the pointer to the source #GstPad object of the element.
   *
   * Since: 0.10.36
   */
- #define GST_BASE_AUDIO_DECODER_SRC_PAD(obj)         (((GstBaseAudioDecoder *) (obj))->srcpad)
+ #define GST_AUDIO_DECODER_SRC_PAD(obj)         (((GstAudioDecoder *) (obj))->srcpad)
  
  /**
-  * GST_BASE_AUDIO_DECODER_SINK_PAD:
+  * GST_AUDIO_DECODER_SINK_PAD:
   * @obj: base audio codec instance
   *
   * Gives the pointer to the sink #GstPad object of the element.
   *
   * Since: 0.10.36
   */
- #define GST_BASE_AUDIO_DECODER_SINK_PAD(obj)        (((GstBaseAudioDecoder *) (obj))->sinkpad)
+ #define GST_AUDIO_DECODER_SINK_PAD(obj)        (((GstAudioDecoder *) (obj))->sinkpad)
  
- typedef struct _GstBaseAudioDecoder GstBaseAudioDecoder;
- typedef struct _GstBaseAudioDecoderClass GstBaseAudioDecoderClass;
+ typedef struct _GstAudioDecoder GstAudioDecoder;
+ typedef struct _GstAudioDecoderClass GstAudioDecoderClass;
  
- typedef struct _GstBaseAudioDecoderPrivate GstBaseAudioDecoderPrivate;
+ typedef struct _GstAudioDecoderPrivate GstAudioDecoderPrivate;
  
  /* do not use this one, use macro below */
- GstFlowReturn _gst_base_audio_decoder_error (GstBaseAudioDecoder *dec, gint weight,
-                                             GQuark domain, gint code,
-                                             gchar *txt, gchar *debug,
-                                             const gchar *file, const gchar *function,
-                                             gint line);
+ GstFlowReturn _gst_audio_decoder_error (GstAudioDecoder *dec, gint weight,
+                                         GQuark domain, gint code,
+                                         gchar *txt, gchar *debug,
+                                         const gchar *file, const gchar *function,
+                                         gint line);
  
  /**
-  * GST_BASE_AUDIO_DECODER_ERROR:
+  * GST_AUDIO_DECODER_ERROR:
   * @el:     the base audio decoder element that generates the error
   * @weight: element defined weight of the error, added to error count
   * @domain: like CORE, LIBRARY, RESOURCE or STREAM (see #gstreamer-GstGError)
   *
   * Since: 0.10.36
   */
- #define GST_BASE_AUDIO_DECODER_ERROR(el, w, domain, code, text, debug, ret) \
+ #define GST_AUDIO_DECODER_ERROR(el, weight, domain, code, text, debug, ret) \
  G_STMT_START {                                                              \
    gchar *__txt = _gst_element_error_printf text;                            \
    gchar *__dbg = _gst_element_error_printf debug;                           \
-   GstBaseAudioDecoder *dec = GST_BASE_AUDIO_DECODER (el);                   \
-   ret = _gst_base_audio_decoder_error (dec, w, GST_ ## domain ## _ERROR,    \
+   GstAudioDecoder *dec = GST_AUDIO_DECODER (el);                   \
+   ret = _gst_audio_decoder_error (dec, weight, GST_ ## domain ## _ERROR,    \
        GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__,            \
        GST_FUNCTION, __LINE__);                                              \
  } G_STMT_END
  
  /**
-  * GstBaseAudioDecoder:
+  * GstAudioDecoder:
   *
-  * The opaque #GstBaseAudioDecoder data structure.
+  * The opaque #GstAudioDecoder data structure.
   *
   * Since: 0.10.36
   */
- struct _GstBaseAudioDecoder
+ struct _GstAudioDecoder
  {
    GstElement element;
  
    GstSegment      segment;
  
    /*< private >*/
-   GstBaseAudioDecoderPrivate *priv;
+   GstAudioDecoderPrivate *priv;
    gpointer       _gst_reserved[GST_PADDING_LARGE];
  };
  
  /**
-  * GstBaseAudioDecoderClass:
+  * GstAudioDecoderClass:
+  * @element_class:  The parent class structure
   * @start:          Optional.
   *                  Called when the element starts processing.
   *                  Allows opening external resources.
   *
   * Since: 0.10.36
   */
- struct _GstBaseAudioDecoderClass
+ struct _GstAudioDecoderClass
  {
-   GstElementClass parent_class;
+   GstElementClass element_class;
  
    /*< public >*/
    /* virtual methods for subclasses */
  
-   gboolean      (*start)              (GstBaseAudioDecoder *dec);
+   gboolean      (*start)              (GstAudioDecoder *dec);
  
-   gboolean      (*stop)               (GstBaseAudioDecoder *dec);
+   gboolean      (*stop)               (GstAudioDecoder *dec);
  
-   gboolean      (*set_format)         (GstBaseAudioDecoder *dec,
+   gboolean      (*set_format)         (GstAudioDecoder *dec,
                                         GstCaps *caps);
  
-   GstFlowReturn (*parse)              (GstBaseAudioDecoder *dec,
+   GstFlowReturn (*parse)              (GstAudioDecoder *dec,
                                         GstAdapter *adapter,
                                         gint *offset, gint *length);
  
-   GstFlowReturn (*handle_frame)       (GstBaseAudioDecoder *dec,
+   GstFlowReturn (*handle_frame)       (GstAudioDecoder *dec,
                                         GstBuffer *buffer);
  
-   void          (*flush)              (GstBaseAudioDecoder *dec, gboolean hard);
+   void          (*flush)              (GstAudioDecoder *dec, gboolean hard);
  
-   GstFlowReturn (*pre_push)           (GstBaseAudioDecoder *dec,
+   GstFlowReturn (*pre_push)           (GstAudioDecoder *dec,
                                         GstBuffer **buffer);
  
-   gboolean      (*event)              (GstBaseAudioDecoder *dec,
+   gboolean      (*event)              (GstAudioDecoder *dec,
                                         GstEvent *event);
  
    /*< private >*/
    gpointer       _gst_reserved[GST_PADDING_LARGE];
  };
  
- gboolean          gst_base_audio_decoder_src_setcaps  (GstBaseAudioDecoder * dec,
-                                                        GstCaps * caps);
- GstFlowReturn     gst_base_audio_decoder_finish_frame (GstBaseAudioDecoder * dec,
-                                                        GstBuffer * buf, gint frames);
+ GType             gst_audio_decoder_get_type (void);
+ GstFlowReturn     gst_audio_decoder_finish_frame (GstAudioDecoder * dec,
 -                                                       GstBuffer * buf, gint frames);
++                                                  GstBuffer * buf, gint frames);
  
  /* context parameters */
- GstAudioInfo    * gst_base_audio_decoder_get_audio_info (GstBaseAudioDecoder * dec);
+ GstAudioInfo    * gst_audio_decoder_get_audio_info (GstAudioDecoder * dec);
+ void              gst_audio_decoder_set_plc_aware  (GstAudioDecoder * dec,
+                                                     gboolean          plc);
+ gint              gst_audio_decoder_get_plc_aware  (GstAudioDecoder * dec);
+ void              gst_audio_decoder_set_byte_time  (GstAudioDecoder * dec,
+                                                     gboolean          enabled);
  
- void              gst_base_audio_decoder_set_plc_aware (GstBaseAudioDecoder * dec,
-                                                         gboolean plc);
- gint              gst_base_audio_decoder_get_plc_aware (GstBaseAudioDecoder * dec);
+ gint              gst_audio_decoder_get_byte_time  (GstAudioDecoder * dec);
  
- void              gst_base_audio_decoder_set_byte_time (GstBaseAudioDecoder * dec,
-                                                         gboolean enabled);
- gint              gst_base_audio_decoder_get_byte_time (GstBaseAudioDecoder * dec);
+ gint              gst_audio_decoder_get_delay      (GstAudioDecoder * dec);
  
- gint              gst_base_audio_decoder_get_delay (GstBaseAudioDecoder * dec);
+ void              gst_audio_decoder_set_max_errors (GstAudioDecoder * dec,
+                                                    gint               num);
  
- void              gst_base_audio_decoder_set_max_errors (GstBaseAudioDecoder * enc,
-                                                          gint num);
- gint              gst_base_audio_decoder_get_max_errors (GstBaseAudioDecoder * dec);
+ gint              gst_audio_decoder_get_max_errors (GstAudioDecoder * dec);
  
- void              gst_base_audio_decoder_set_latency (GstBaseAudioDecoder * dec,
-                                                       GstClockTime min, GstClockTime max);
- void              gst_base_audio_decoder_get_latency (GstBaseAudioDecoder * dec,
-                                                       GstClockTime * min, GstClockTime * max);
+ void              gst_audio_decoder_set_latency (GstAudioDecoder * dec,
+                                                  GstClockTime      min,
+                                                  GstClockTime      max);
  
- void              gst_base_audio_decoder_get_parse_state (GstBaseAudioDecoder * dec,
-                                                           gboolean * sync, gboolean * eos);
+ void              gst_audio_decoder_get_latency (GstAudioDecoder * dec,
+                                                  GstClockTime    * min,
+                                                  GstClockTime    * max);
+ void              gst_audio_decoder_get_parse_state (GstAudioDecoder * dec,
+                                                      gboolean        * sync,
+                                                      gboolean        * eos);
  
  
  /* object properties */
- void              gst_base_audio_decoder_set_plc (GstBaseAudioDecoder * dec,
-                                                   gboolean enabled);
- gboolean          gst_base_audio_decoder_get_plc (GstBaseAudioDecoder * dec);
+ void              gst_audio_decoder_set_plc (GstAudioDecoder * dec,
+                                              gboolean          enabled);
  
- void              gst_base_audio_decoder_set_min_latency (GstBaseAudioDecoder * dec,
-                                                           gint64 num);
- gint64            gst_base_audio_decoder_get_min_latency (GstBaseAudioDecoder * dec);
+ gboolean          gst_audio_decoder_get_plc (GstAudioDecoder * dec);
  
- void              gst_base_audio_decoder_set_tolerance (GstBaseAudioDecoder * dec,
-                                                         gint64 tolerance);
+ void              gst_audio_decoder_set_min_latency (GstAudioDecoder * dec,
+                                                      gint64            num);
  
- gint64            gst_base_audio_decoder_get_tolerance (GstBaseAudioDecoder * dec);
+ gint64            gst_audio_decoder_get_min_latency (GstAudioDecoder * dec);
  
- GType gst_base_audio_decoder_get_type (void);
+ void              gst_audio_decoder_set_tolerance   (GstAudioDecoder * dec,
+                                                      gint64            tolerance);
  
- G_END_DECLS
+ gint64            gst_audio_decoder_get_tolerance   (GstAudioDecoder * dec);
  
- #endif
+ G_END_DECLS
  
+ #endif /* _GST_AUDIO_DECODER_H_ */
@@@ -20,7 -20,7 +20,7 @@@
   */
  
  /**
-  * SECTION:gstbaseaudioencoder
+  * SECTION:gstaudioencoder
   * @short_description: Base class for audio encoders
   * @see_also: #GstBaseTransform
   * @since: 0.10.36
   * This base class is for audio encoders turning raw audio samples into
   * encoded audio data.
   *
-  * GstBaseAudioEncoder and subclass should cooperate as follows.
+  * GstAudioEncoder and subclass should cooperate as follows.
   * <orderedlist>
   * <listitem>
   *   <itemizedlist><title>Configuration</title>
   *   <listitem><para>
-  *     Initially, GstBaseAudioEncoder calls @start when the encoder element
+  *     Initially, GstAudioEncoder calls @start when the encoder element
   *     is activated, which allows subclass to perform any global setup.
   *   </para></listitem>
   *   <listitem><para>
-  *     GstBaseAudioEncoder calls @set_format to inform subclass of the format
+  *     GstAudioEncoder calls @set_format to inform subclass of the format
   *     of input audio data that it is about to receive.  Subclass should
   *     setup for encoding and configure various base class parameters
   *     appropriately, notably those directing desired input data handling.
   *     parameters require reconfiguration.
   *   </para></listitem>
   *   <listitem><para>
-  *     GstBaseAudioEncoder calls @stop at end of all processing.
+  *     GstAudioEncoder calls @stop at end of all processing.
   *   </para></listitem>
   *   </itemizedlist>
   * </listitem>
-  * As of configuration stage, and throughout processing, GstBaseAudioEncoder
+  * As of configuration stage, and throughout processing, GstAudioEncoder
   * maintains various parameters that provide required context,
   * e.g. describing the format of input audio data.
   * Conversely, subclass can and should configure these context parameters
@@@ -63,7 -63,7 +63,7 @@@
   *     </para></listitem>
   *     <listitem><para>
   *       If codec processing results in encoded data, subclass should call
-  *       @gst_base_audio_encoder_finish_frame to have encoded data pushed
+  *       @gst_audio_encoder_finish_frame to have encoded data pushed
   *       downstream.  Alternatively, it might also call to indicate dropped
   *       (non-encoded) samples.
   *     </para></listitem>
@@@ -72,7 -72,7 +72,7 @@@
   *       it is passed to @pre_push.
   *     </para></listitem>
   *     <listitem><para>
-  *       During the parsing process GstBaseAudioEncoderClass will handle both
+  *       During the parsing process GstAudioEncoderClass will handle both
   *       srcpad and sinkpad events. Sink events will be passed to subclass
   *       if @event callback has been provided.
   *     </para></listitem>
@@@ -81,7 -81,7 +81,7 @@@
   * <listitem>
   *   <itemizedlist><title>Shutdown phase</title>
   *   <listitem><para>
-  *     GstBaseAudioEncoder class calls @stop to inform the subclass that data
+  *     GstAudioEncoder class calls @stop to inform the subclass that data
   *     parsing will be stopped.
   *   </para></listitem>
   *   </itemizedlist>
@@@ -92,7 -92,7 +92,7 @@@
   * source and sink pads. The pads need to be named "sink" and "src". It also 
   * needs to set the fixed caps on srcpad, when the format is ensured.  This
   * is typically when base class calls subclass' @set_format function, though
-  * it might be delayed until calling @gst_base_audio_encoder_finish_frame.
+  * it might be delayed until calling @gst_audio_encoder_finish_frame.
   *
   * In summary, above process should have subclass concentrating on
   * codec data processing while leaving other matters to base class,
   *
   * In particular, base class will either favor tracking upstream timestamps
   * (at the possible expense of jitter) or aim to arrange for a perfect stream of
-  * output timestamps, depending on #GstBaseAudioEncoder:perfect-ts.
+  * output timestamps, depending on #GstAudioEncoder:perfect-timestamp.
   * However, in the latter case, the input may not be so perfect or ideal, which
   * is handled as follows.  An input timestamp is compared with the expected
   * timestamp as dictated by input sample stream and if the deviation is less
-  * than #GstBaseAudioEncoder:tolerance, the deviation is discarded.
+  * than #GstAudioEncoder:tolerance, the deviation is discarded.
   * Otherwise, it is considered a discontuinity and subsequent output timestamp
   * is resynced to the new position after performing configured discontinuity
-  * processing.  In the non-perfect-ts case, an upstream variation exceeding
-  * tolerance only leads to marking DISCONT on subsequent outgoing
+  * processing.  In the non-perfect-timestamp case, an upstream variation
+  * exceeding tolerance only leads to marking DISCONT on subsequent outgoing
   * (while timestamps are adjusted to upstream regardless of variation).
-  * While DISCONT is also marked in the perfect-ts case, this one optionally
-  * (see #GstBaseAudioEncoder:hard-resync)
+  * While DISCONT is also marked in the perfect-timestamp case, this one
+  * optionally (see #GstAudioEncoder:hard-resync)
   * performs some additional steps, such as clipping of (early) input samples
   * or draining all currently remaining input data, depending on the direction
   * of the discontuinity.
   *   </para></listitem>
   *   <listitem><para>
   *      Accept data in @handle_frame and provide encoded results to
-  *      @gst_base_audio_encoder_finish_frame.
+  *      @gst_audio_encoder_finish_frame.
   *   </para></listitem>
   * </itemizedlist>
   *
  #  include "config.h"
  #endif
  
- #include "gstbaseaudioencoder.h"
 -#define GST_USE_UNSTABLE_API
+ #include "gstaudioencoder.h"
  #include <gst/base/gstadapter.h>
  #include <gst/audio/audio.h>
  
  #include <string.h>
  
  
- GST_DEBUG_CATEGORY_STATIC (gst_base_audio_encoder_debug);
- #define GST_CAT_DEFAULT gst_base_audio_encoder_debug
+ GST_DEBUG_CATEGORY_STATIC (gst_audio_encoder_debug);
+ #define GST_CAT_DEFAULT gst_audio_encoder_debug
  
- #define GST_BASE_AUDIO_ENCODER_GET_PRIVATE(obj)  \
-     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_ENCODER, \
-         GstBaseAudioEncoderPrivate))
+ #define GST_AUDIO_ENCODER_GET_PRIVATE(obj)  \
+     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_AUDIO_ENCODER, \
+         GstAudioEncoderPrivate))
  
  enum
  {
  #define DEFAULT_HARD_RESYNC  FALSE
  #define DEFAULT_TOLERANCE    40000000
  
- typedef struct _GstBaseAudioEncoderContext
+ typedef struct _GstAudioEncoderContext
  {
    /* input */
    GstAudioInfo info;
    /* MT-protected (with LOCK) */
    GstClockTime min_latency;
    GstClockTime max_latency;
- } GstBaseAudioEncoderContext;
+ } GstAudioEncoderContext;
  
- struct _GstBaseAudioEncoderPrivate
+ struct _GstAudioEncoderPrivate
  {
    /* activation status */
    gboolean active;
    guint64 bytes_out;
  
    /* context storage */
-   GstBaseAudioEncoderContext ctx;
+   GstAudioEncoderContext ctx;
  
    /* properties */
    gint64 tolerance;
  
  static GstElementClass *parent_class = NULL;
  
- static void gst_base_audio_encoder_class_init (GstBaseAudioEncoderClass *
-     klass);
- static void gst_base_audio_encoder_init (GstBaseAudioEncoder * parse,
-     GstBaseAudioEncoderClass * klass);
+ static void gst_audio_encoder_class_init (GstAudioEncoderClass * klass);
+ static void gst_audio_encoder_init (GstAudioEncoder * parse,
+     GstAudioEncoderClass * klass);
  
  GType
- gst_base_audio_encoder_get_type (void)
+ gst_audio_encoder_get_type (void)
  {
-   static GType base_audio_encoder_type = 0;
+   static GType audio_encoder_type = 0;
  
-   if (!base_audio_encoder_type) {
-     static const GTypeInfo base_audio_encoder_info = {
-       sizeof (GstBaseAudioEncoderClass),
+   if (!audio_encoder_type) {
+     static const GTypeInfo audio_encoder_info = {
+       sizeof (GstAudioEncoderClass),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
-       (GClassInitFunc) gst_base_audio_encoder_class_init,
+       (GClassInitFunc) gst_audio_encoder_class_init,
        NULL,
        NULL,
-       sizeof (GstBaseAudioEncoder),
+       sizeof (GstAudioEncoder),
        0,
-       (GInstanceInitFunc) gst_base_audio_encoder_init,
+       (GInstanceInitFunc) gst_audio_encoder_init,
      };
      const GInterfaceInfo preset_interface_info = {
        NULL,                     /* interface_init */
        NULL                      /* interface_data */
      };
  
-     base_audio_encoder_type = g_type_register_static (GST_TYPE_ELEMENT,
-         "GstBaseAudioEncoder", &base_audio_encoder_info, G_TYPE_FLAG_ABSTRACT);
+     audio_encoder_type = g_type_register_static (GST_TYPE_ELEMENT,
+         "GstAudioEncoder", &audio_encoder_info, G_TYPE_FLAG_ABSTRACT);
  
-     g_type_add_interface_static (base_audio_encoder_type, GST_TYPE_PRESET,
+     g_type_add_interface_static (audio_encoder_type, GST_TYPE_PRESET,
          &preset_interface_info);
    }
-   return base_audio_encoder_type;
+   return audio_encoder_type;
  }
  
- static void gst_base_audio_encoder_finalize (GObject * object);
- static void gst_base_audio_encoder_reset (GstBaseAudioEncoder * enc,
-     gboolean full);
+ static void gst_audio_encoder_finalize (GObject * object);
+ static void gst_audio_encoder_reset (GstAudioEncoder * enc, gboolean full);
  
- static void gst_base_audio_encoder_set_property (GObject * object,
+ static void gst_audio_encoder_set_property (GObject * object,
      guint prop_id, const GValue * value, GParamSpec * pspec);
- static void gst_base_audio_encoder_get_property (GObject * object,
+ static void gst_audio_encoder_get_property (GObject * object,
      guint prop_id, GValue * value, GParamSpec * pspec);
  
- static gboolean gst_base_audio_encoder_sink_activate_push (GstPad * pad,
+ static gboolean gst_audio_encoder_sink_activate_push (GstPad * pad,
      gboolean active);
  
- static gboolean gst_base_audio_encoder_sink_event (GstPad * pad,
-     GstEvent * event);
- static GstFlowReturn gst_base_audio_encoder_chain (GstPad * pad,
-     GstBuffer * buffer);
- static gboolean gst_base_audio_encoder_src_query (GstPad * pad,
-     GstQuery * query);
- static gboolean gst_base_audio_encoder_sink_query (GstPad * pad,
-     GstQuery * query);
- static const GstQueryType *gst_base_audio_encoder_get_query_types (GstPad *
-     pad);
- static GstCaps *gst_base_audio_encoder_sink_getcaps (GstPad * pad,
-     GstCaps * filter);
+ static gboolean gst_audio_encoder_sink_event (GstPad * pad, GstEvent * event);
 -static gboolean gst_audio_encoder_sink_setcaps (GstPad * pad, GstCaps * caps);
++static gboolean gst_audio_encoder_sink_setcaps (GstAudioEncoder * enc,
++    GstCaps * caps);
+ static GstFlowReturn gst_audio_encoder_chain (GstPad * pad, GstBuffer * buffer);
+ static gboolean gst_audio_encoder_src_query (GstPad * pad, GstQuery * query);
+ static gboolean gst_audio_encoder_sink_query (GstPad * pad, GstQuery * query);
+ static const GstQueryType *gst_audio_encoder_get_query_types (GstPad * pad);
 -static GstCaps *gst_audio_encoder_sink_getcaps (GstPad * pad);
 -
++static GstCaps *gst_audio_encoder_sink_getcaps (GstPad * pad, GstCaps * filter);
  
  static void
- gst_base_audio_encoder_class_init (GstBaseAudioEncoderClass * klass)
+ gst_audio_encoder_class_init (GstAudioEncoderClass * klass)
  {
    GObjectClass *gobject_class;
  
    gobject_class = G_OBJECT_CLASS (klass);
    parent_class = g_type_class_peek_parent (klass);
  
-   GST_DEBUG_CATEGORY_INIT (gst_base_audio_encoder_debug, "baseaudioencoder", 0,
-       "baseaudioencoder element");
+   GST_DEBUG_CATEGORY_INIT (gst_audio_encoder_debug, "audioencoder", 0,
+       "audio encoder base class");
  
-   g_type_class_add_private (klass, sizeof (GstBaseAudioEncoderPrivate));
+   g_type_class_add_private (klass, sizeof (GstAudioEncoderPrivate));
  
-   gobject_class->set_property = gst_base_audio_encoder_set_property;
-   gobject_class->get_property = gst_base_audio_encoder_get_property;
+   gobject_class->set_property = gst_audio_encoder_set_property;
+   gobject_class->get_property = gst_audio_encoder_get_property;
  
-   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_audio_encoder_finalize);
+   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_audio_encoder_finalize);
  
    /* properties */
    g_object_class_install_property (gobject_class, PROP_PERFECT_TS,
            DEFAULT_PERFECT_TS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
    g_object_class_install_property (gobject_class, PROP_GRANULE,
        g_param_spec_boolean ("mark-granule", "Granule Marking",
-           "Apply granule semantics to buffer metadata (implies perfect-ts)",
+           "Apply granule semantics to buffer metadata (implies perfect-timestamp)",
            DEFAULT_GRANULE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
    g_object_class_install_property (gobject_class, PROP_HARD_RESYNC,
        g_param_spec_boolean ("hard-resync", "Hard Resync",
  }
  
  static void
- gst_base_audio_encoder_init (GstBaseAudioEncoder * enc,
-     GstBaseAudioEncoderClass * bclass)
+ gst_audio_encoder_init (GstAudioEncoder * enc, GstAudioEncoderClass * bclass)
  {
    GstPadTemplate *pad_template;
  
-   GST_DEBUG_OBJECT (enc, "gst_base_audio_encoder_init");
+   GST_DEBUG_OBJECT (enc, "gst_audio_encoder_init");
  
-   enc->priv = GST_BASE_AUDIO_ENCODER_GET_PRIVATE (enc);
+   enc->priv = GST_AUDIO_ENCODER_GET_PRIVATE (enc);
  
    /* only push mode supported */
    pad_template =
    g_return_if_fail (pad_template != NULL);
    enc->sinkpad = gst_pad_new_from_template (pad_template, "sink");
    gst_pad_set_event_function (enc->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_encoder_sink_event));
+       GST_DEBUG_FUNCPTR (gst_audio_encoder_sink_event));
 -  gst_pad_set_setcaps_function (enc->sinkpad,
 -      GST_DEBUG_FUNCPTR (gst_audio_encoder_sink_setcaps));
    gst_pad_set_getcaps_function (enc->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_encoder_sink_getcaps));
+       GST_DEBUG_FUNCPTR (gst_audio_encoder_sink_getcaps));
    gst_pad_set_query_function (enc->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_encoder_sink_query));
+       GST_DEBUG_FUNCPTR (gst_audio_encoder_sink_query));
    gst_pad_set_chain_function (enc->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_encoder_chain));
+       GST_DEBUG_FUNCPTR (gst_audio_encoder_chain));
    gst_pad_set_activatepush_function (enc->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_encoder_sink_activate_push));
+       GST_DEBUG_FUNCPTR (gst_audio_encoder_sink_activate_push));
    gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
  
    GST_DEBUG_OBJECT (enc, "sinkpad created");
    g_return_if_fail (pad_template != NULL);
    enc->srcpad = gst_pad_new_from_template (pad_template, "src");
    gst_pad_set_query_function (enc->srcpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_encoder_src_query));
+       GST_DEBUG_FUNCPTR (gst_audio_encoder_src_query));
    gst_pad_set_query_type_function (enc->srcpad,
-       GST_DEBUG_FUNCPTR (gst_base_audio_encoder_get_query_types));
+       GST_DEBUG_FUNCPTR (gst_audio_encoder_get_query_types));
    gst_pad_use_fixed_caps (enc->srcpad);
    gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
    GST_DEBUG_OBJECT (enc, "src created");
    enc->priv->tolerance = DEFAULT_TOLERANCE;
  
    /* init state */
-   gst_base_audio_encoder_reset (enc, TRUE);
+   gst_audio_encoder_reset (enc, TRUE);
    GST_DEBUG_OBJECT (enc, "init ok");
  }
  
  static void
- gst_base_audio_encoder_reset (GstBaseAudioEncoder * enc, gboolean full)
+ gst_audio_encoder_reset (GstAudioEncoder * enc, gboolean full)
  {
    GST_OBJECT_LOCK (enc);
  
      enc->priv->active = FALSE;
      enc->priv->samples_in = 0;
      enc->priv->bytes_out = 0;
 -    gst_audio_info_clear (&enc->priv->ctx.info);
 +    gst_audio_info_init (&enc->priv->ctx.info);
      memset (&enc->priv->ctx, 0, sizeof (enc->priv->ctx));
    }
  
  }
  
  static void
- gst_base_audio_encoder_finalize (GObject * object)
+ gst_audio_encoder_finalize (GObject * object)
  {
-   GstBaseAudioEncoder *enc = GST_BASE_AUDIO_ENCODER (object);
+   GstAudioEncoder *enc = GST_AUDIO_ENCODER (object);
  
    g_object_unref (enc->priv->adapter);
  
  }
  
  /**
-  * gst_base_audio_encoder_finish_frame:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_finish_frame:
+  * @enc: a #GstAudioEncoder
   * @buffer: encoded data
   * @samples: number of samples (per channel) represented by encoded data
   *
   * Since: 0.10.36
   */
  GstFlowReturn
- gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
+ gst_audio_encoder_finish_frame (GstAudioEncoder * enc, GstBuffer * buf,
      gint samples)
  {
-   GstBaseAudioEncoderClass *klass;
-   GstBaseAudioEncoderPrivate *priv;
-   GstBaseAudioEncoderContext *ctx;
+   GstAudioEncoderClass *klass;
+   GstAudioEncoderPrivate *priv;
+   GstAudioEncoderContext *ctx;
    GstFlowReturn ret = GST_FLOW_OK;
  
-   klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
+   klass = GST_AUDIO_ENCODER_GET_CLASS (enc);
    priv = enc->priv;
    ctx = &enc->priv->ctx;
  
    /* subclass should know what it is producing by now */
 -  g_return_val_if_fail (GST_PAD_CAPS (enc->srcpad) != NULL, GST_FLOW_ERROR);
 +  g_return_val_if_fail (gst_pad_has_current_caps (enc->srcpad), GST_FLOW_ERROR);
    /* subclass should not hand us no data */
 -  g_return_val_if_fail (buf == NULL || GST_BUFFER_SIZE (buf) > 0,
 +  g_return_val_if_fail (buf == NULL || gst_buffer_get_size (buf) > 0,
        GST_FLOW_ERROR);
  
    GST_LOG_OBJECT (enc, "accepting %d bytes encoded data as %d samples",
 -      buf ? GST_BUFFER_SIZE (buf) : -1, samples);
 +      buf ? gst_buffer_get_size (buf) : -1, samples);
  
    /* mark subclass still alive and providing */
    priv->got_data = TRUE;
  
    /* collect output */
    if (G_LIKELY (buf)) {
 -    GST_LOG_OBJECT (enc, "taking %d bytes for output", GST_BUFFER_SIZE (buf));
 -    buf = gst_buffer_make_metadata_writable (buf);
 +    gsize size;
 +
 +    size = gst_buffer_get_size (buf);
 +
 +    GST_LOG_OBJECT (enc, "taking %d bytes for output", size);
 +    buf = gst_buffer_make_writable (buf);
  
      /* decorate */
 -    gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad));
      if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (priv->base_ts))) {
        /* FIXME ? lookahead could lead to weird ts and duration ?
         * (particularly if not in perfect mode) */
              ctx->info.rate);
        } else {
          GST_BUFFER_OFFSET (buf) = priv->bytes_out;
 -        GST_BUFFER_OFFSET_END (buf) = priv->bytes_out + GST_BUFFER_SIZE (buf);
 +        GST_BUFFER_OFFSET_END (buf) = priv->bytes_out + size;
        }
      }
  
 -    priv->bytes_out += GST_BUFFER_SIZE (buf);
 +    priv->bytes_out += size;
  
      if (G_UNLIKELY (priv->discont)) {
        GST_LOG_OBJECT (enc, "marking discont");
      }
  
      GST_LOG_OBJECT (enc, "pushing buffer of size %d with ts %" GST_TIME_FORMAT
 -        ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
 +        ", duration %" GST_TIME_FORMAT, size,
          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
          GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
  
@@@ -654,16 -646,16 +646,16 @@@ overflow
    * (i.e. really returned by encoder subclass)
    * - start + offset is what needs to be fed to subclass next */
  static GstFlowReturn
- gst_base_audio_encoder_push_buffers (GstBaseAudioEncoder * enc, gboolean force)
+ gst_audio_encoder_push_buffers (GstAudioEncoder * enc, gboolean force)
  {
-   GstBaseAudioEncoderClass *klass;
-   GstBaseAudioEncoderPrivate *priv;
-   GstBaseAudioEncoderContext *ctx;
+   GstAudioEncoderClass *klass;
+   GstAudioEncoderPrivate *priv;
+   GstAudioEncoderContext *ctx;
    gint av, need;
    GstBuffer *buf;
    GstFlowReturn ret = GST_FLOW_OK;
  
-   klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
+   klass = GST_AUDIO_ENCODER_GET_CLASS (enc);
  
    g_return_val_if_fail (klass->handle_frame != NULL, GST_FLOW_ERROR);
  
      }
  
      if (need) {
 -      buf = gst_buffer_new ();
 -      GST_BUFFER_DATA (buf) = (guint8 *)
 -          gst_adapter_peek (priv->adapter, priv->offset + need) + priv->offset;
 -      GST_BUFFER_SIZE (buf) = need;
 +      const guint8 *data;
 +
 +      data = gst_adapter_map (priv->adapter, priv->offset + need);
 +      buf =
 +          gst_buffer_new_wrapped_full ((gpointer) data, NULL, priv->offset,
 +          need);
      }
  
      GST_LOG_OBJECT (enc, "providing subclass with %d bytes at offset %d",
      priv->got_data = FALSE;
      ret = klass->handle_frame (enc, buf);
  
 -    if (G_LIKELY (buf))
 +    if (G_LIKELY (buf)) {
        gst_buffer_unref (buf);
 +      gst_adapter_unmap (priv->adapter, 0);
 +    }
  
      /* no data to feed, no leftover provided, then bail out */
      if (G_UNLIKELY (!buf && !priv->got_data)) {
  }
  
  static GstFlowReturn
- gst_base_audio_encoder_drain (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_drain (GstAudioEncoder * enc)
  {
    if (enc->priv->drained)
      return GST_FLOW_OK;
    else
-     return gst_base_audio_encoder_push_buffers (enc, TRUE);
+     return gst_audio_encoder_push_buffers (enc, TRUE);
  }
  
  static void
- gst_base_audio_encoder_set_base_gp (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_set_base_gp (GstAudioEncoder * enc)
  {
    GstClockTime ts;
  
  }
  
  static GstFlowReturn
- gst_base_audio_encoder_chain (GstPad * pad, GstBuffer * buffer)
+ gst_audio_encoder_chain (GstPad * pad, GstBuffer * buffer)
  {
-   GstBaseAudioEncoder *enc;
-   GstBaseAudioEncoderPrivate *priv;
-   GstBaseAudioEncoderContext *ctx;
+   GstAudioEncoder *enc;
+   GstAudioEncoderPrivate *priv;
+   GstAudioEncoderContext *ctx;
    GstFlowReturn ret = GST_FLOW_OK;
    gboolean discont;
 +  gsize size;
  
-   enc = GST_BASE_AUDIO_ENCODER (GST_OBJECT_PARENT (pad));
+   enc = GST_AUDIO_ENCODER (GST_OBJECT_PARENT (pad));
  
    priv = enc->priv;
    ctx = &enc->priv->ctx;
    if (!ctx->info.bpf)
      goto not_negotiated;
  
 +  size = gst_buffer_get_size (buffer);
 +
    GST_LOG_OBJECT (enc,
        "received buffer of size %d with ts %" GST_TIME_FORMAT
 -      ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer),
 +      ", duration %" GST_TIME_FORMAT, size,
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
  
    /* input shoud be whole number of sample frames */
 -  if (GST_BUFFER_SIZE (buffer) % ctx->info.bpf)
 +  if (size % ctx->info.bpf)
      goto wrong_buffer;
  
  #ifndef GST_DISABLE_GST_DEBUG
      GstClockTimeDiff diff;
  
      /* verify buffer duration */
 -    duration = gst_util_uint64_scale (GST_BUFFER_SIZE (buffer), GST_SECOND,
 +    duration = gst_util_uint64_scale (size, GST_SECOND,
          ctx->info.rate * ctx->info.bpf);
      diff = GST_CLOCK_DIFF (duration, GST_BUFFER_DURATION (buffer));
      if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE &&
      goto done;
    }
  
 +  size = gst_buffer_get_size (buffer);
 +
    GST_LOG_OBJECT (enc,
        "buffer after segment clipping has size %d with ts %" GST_TIME_FORMAT
 -      ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer),
 +      ", duration %" GST_TIME_FORMAT, size,
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
  
      priv->base_ts = GST_BUFFER_TIMESTAMP (buffer);
      GST_DEBUG_OBJECT (enc, "new base ts %" GST_TIME_FORMAT,
          GST_TIME_ARGS (priv->base_ts));
-     gst_base_audio_encoder_set_base_gp (enc);
+     gst_audio_encoder_set_base_gp (enc);
    }
  
    /* check for continuity;
  
          diff_bytes =
              GST_CLOCK_TIME_TO_FRAMES (-diff, ctx->info.rate) * ctx->info.bpf;
 -        if (diff_bytes >= GST_BUFFER_SIZE (buffer)) {
 +        if (diff_bytes >= size) {
            gst_buffer_unref (buffer);
            goto done;
          }
 -        buffer = gst_buffer_make_metadata_writable (buffer);
 -        GST_BUFFER_DATA (buffer) += diff_bytes;
 -        GST_BUFFER_SIZE (buffer) -= diff_bytes;
 +        buffer = gst_buffer_make_writable (buffer);
 +        gst_buffer_resize (buffer, diff_bytes, size - diff_bytes);
  
          GST_BUFFER_TIMESTAMP (buffer) += diff;
          /* care even less about duration after this */
        } else {
          /* drain stuff prior to resync */
-         gst_base_audio_encoder_drain (enc);
+         gst_audio_encoder_drain (enc);
        }
      }
      /* now re-sync ts */
      priv->base_ts += diff;
-     gst_base_audio_encoder_set_base_gp (enc);
+     gst_audio_encoder_set_base_gp (enc);
      priv->discont |= discont;
    }
  
    /* new stuff, so we can push subclass again */
    enc->priv->drained = FALSE;
  
-   ret = gst_base_audio_encoder_push_buffers (enc, FALSE);
+   ret = gst_audio_encoder_push_buffers (enc, FALSE);
  
  done:
    GST_LOG_OBJECT (enc, "chain leaving");
@@@ -937,7 -921,7 +929,7 @@@ not_negotiated
  wrong_buffer:
    {
      GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
 -        ("buffer size %d not a multiple of %d", GST_BUFFER_SIZE (buffer),
 +        ("buffer size %d not a multiple of %d", gst_buffer_get_size (buffer),
              ctx->info.bpf));
      gst_buffer_unref (buffer);
      return GST_FLOW_ERROR;
@@@ -962,20 -946,23 +954,20 @@@ audio_info_is_equal (GstAudioInfo * fro
  }
  
  static gboolean
- gst_base_audio_encoder_sink_setcaps (GstBaseAudioEncoder * enc, GstCaps * caps)
 -gst_audio_encoder_sink_setcaps (GstPad * pad, GstCaps * caps)
++gst_audio_encoder_sink_setcaps (GstAudioEncoder * enc, GstCaps * caps)
  {
-   GstBaseAudioEncoderClass *klass;
-   GstBaseAudioEncoderContext *ctx;
 -  GstAudioEncoder *enc;
+   GstAudioEncoderClass *klass;
+   GstAudioEncoderContext *ctx;
 -  GstAudioInfo *state, *old_state;
 +  GstAudioInfo state;
    gboolean res = TRUE, changed = FALSE;
    guint old_rate;
  
-   klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
 -  enc = GST_AUDIO_ENCODER (GST_PAD_PARENT (pad));
+   klass = GST_AUDIO_ENCODER_GET_CLASS (enc);
  
    /* subclass must do something here ... */
    g_return_val_if_fail (klass->set_format != NULL, FALSE);
  
    ctx = &enc->priv->ctx;
 -  state = &ctx->info;
  
    GST_DEBUG_OBJECT (enc, "caps: %" GST_PTR_FORMAT, caps);
  
      goto refuse_caps;
  
    /* adjust ts tracking to new sample rate */
 -  old_rate = GST_AUDIO_INFO_RATE (state);
 +  old_rate = GST_AUDIO_INFO_RATE (&ctx->info);
    if (GST_CLOCK_TIME_IS_VALID (enc->priv->base_ts) && old_rate) {
      enc->priv->base_ts +=
          GST_FRAMES_TO_CLOCK_TIME (enc->priv->samples, old_rate);
      enc->priv->samples = 0;
    }
  
 -  old_state = gst_audio_info_copy (state);
 -  if (!gst_audio_info_from_caps (state, caps))
 +  if (!gst_audio_info_from_caps (&state, caps))
      goto refuse_caps;
  
 -  changed = audio_info_is_equal (state, old_state);
 -  gst_audio_info_free (old_state);
 +  changed = audio_info_is_equal (&state, &ctx->info);
  
    if (changed) {
      GstClockTime old_min_latency;
      GstClockTime old_max_latency;
  
      /* drain any pending old data stuff */
-     gst_base_audio_encoder_drain (enc);
+     gst_audio_encoder_drain (enc);
  
      /* context defaults */
      enc->priv->ctx.frame_samples = 0;
      GST_OBJECT_UNLOCK (enc);
  
      if (klass->set_format)
 -      res = klass->set_format (enc, state);
 +      res = klass->set_format (enc, &state);
  
      /* notify if new latency */
      GST_OBJECT_LOCK (enc);
@@@ -1043,8 -1032,8 +1035,8 @@@ refuse_caps
  
  
  /**
-  * gst_base_audio_encoder_proxy_getcaps:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_proxy_getcaps:
+  * @enc: a #GstAudioEncoder
   * @caps: initial caps
   *
   * Returns caps that express @caps (or sink template caps if @caps == NULL)
   * Since: 0.10.36
   */
  GstCaps *
- gst_base_audio_encoder_proxy_getcaps (GstBaseAudioEncoder * enc, GstCaps * caps)
+ gst_audio_encoder_proxy_getcaps (GstAudioEncoder * enc, GstCaps * caps)
  {
    const GstCaps *templ_caps;
    GstCaps *allowed = NULL;
@@@ -1111,20 -1100,20 +1103,20 @@@ done
  }
  
  static GstCaps *
- gst_base_audio_encoder_sink_getcaps (GstPad * pad, GstCaps * filter)
 -gst_audio_encoder_sink_getcaps (GstPad * pad)
++gst_audio_encoder_sink_getcaps (GstPad * pad, GstCaps * filter)
  {
-   GstBaseAudioEncoder *enc;
-   GstBaseAudioEncoderClass *klass;
+   GstAudioEncoder *enc;
+   GstAudioEncoderClass *klass;
    GstCaps *caps;
  
-   enc = GST_BASE_AUDIO_ENCODER (gst_pad_get_parent (pad));
-   klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
+   enc = GST_AUDIO_ENCODER (gst_pad_get_parent (pad));
+   klass = GST_AUDIO_ENCODER_GET_CLASS (enc);
    g_assert (pad == enc->sinkpad);
  
    if (klass->getcaps)
 -    caps = klass->getcaps (enc);
 +    caps = klass->getcaps (enc, filter);
    else
-     caps = gst_base_audio_encoder_proxy_getcaps (enc, NULL);
+     caps = gst_audio_encoder_proxy_getcaps (enc, NULL);
    gst_object_unref (enc);
  
    GST_LOG_OBJECT (enc, "returning caps %" GST_PTR_FORMAT, caps);
  }
  
  static gboolean
- gst_base_audio_encoder_sink_eventfunc (GstBaseAudioEncoder * enc,
-     GstEvent * event)
+ gst_audio_encoder_sink_eventfunc (GstAudioEncoder * enc, GstEvent * event)
  {
-   GstBaseAudioEncoderClass *klass;
+   GstAudioEncoderClass *klass;
    gboolean handled = FALSE;
  
-   klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
+   klass = GST_AUDIO_ENCODER_GET_CLASS (enc);
  
    switch (GST_EVENT_TYPE (event)) {
 -    case GST_EVENT_NEWSEGMENT:
 +    case GST_EVENT_SEGMENT:
      {
 -      GstFormat format;
 -      gdouble rate, arate;
 -      gint64 start, stop, time;
 -      gboolean update;
 -
 -      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
 -          &start, &stop, &time);
 -
 -      if (format == GST_FORMAT_TIME) {
 -        GST_DEBUG_OBJECT (enc, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
 -            " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
 -            ", rate %g, applied_rate %g",
 -            GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time),
 -            rate, arate);
 +      GstSegment seg;
 +
 +      gst_event_copy_segment (event, &seg);
 +
 +      if (seg.format == GST_FORMAT_TIME) {
 +        GST_DEBUG_OBJECT (enc, "received TIME SEGMENT %" GST_PTR_FORMAT, &seg);
        } else {
 -        GST_DEBUG_OBJECT (enc, "received NEW_SEGMENT %" G_GINT64_FORMAT
 -            " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
 -            ", rate %g, applied_rate %g", start, stop, time, rate, arate);
 +        GST_DEBUG_OBJECT (enc, "received SEGMENT %" GST_PTR_FORMAT, &seg);
          GST_DEBUG_OBJECT (enc, "unsupported format; ignoring");
          break;
        }
  
        /* finish current segment */
-       gst_base_audio_encoder_drain (enc);
+       gst_audio_encoder_drain (enc);
        /* reset partially for new segment */
-       gst_base_audio_encoder_reset (enc, FALSE);
+       gst_audio_encoder_reset (enc, FALSE);
        /* and follow along with segment */
 -      gst_segment_set_newsegment_full (&enc->segment, update, rate, arate,
 -          format, start, stop, time);
 +      enc->segment = seg;
        break;
      }
  
        if (!enc->priv->drained && klass->flush)
          klass->flush (enc);
        /* and get (re)set for the sequel */
-       gst_base_audio_encoder_reset (enc, FALSE);
+       gst_audio_encoder_reset (enc, FALSE);
        break;
  
      case GST_EVENT_EOS:
-       gst_base_audio_encoder_drain (enc);
+       gst_audio_encoder_drain (enc);
        break;
  
-       gst_base_audio_encoder_sink_setcaps (enc, caps);
 +    case GST_EVENT_CAPS:
 +    {
 +      GstCaps *caps;
 +
 +      gst_event_parse_caps (event, &caps);
++      gst_audio_encoder_sink_setcaps (enc, caps);
 +      gst_event_unref (event);
 +      handled = TRUE;
 +      break;
 +    }
 +
      default:
        break;
    }
  }
  
  static gboolean
- gst_base_audio_encoder_sink_event (GstPad * pad, GstEvent * event)
+ gst_audio_encoder_sink_event (GstPad * pad, GstEvent * event)
  {
-   GstBaseAudioEncoder *enc;
-   GstBaseAudioEncoderClass *klass;
+   GstAudioEncoder *enc;
+   GstAudioEncoderClass *klass;
    gboolean handled = FALSE;
    gboolean ret = TRUE;
  
-   enc = GST_BASE_AUDIO_ENCODER (gst_pad_get_parent (pad));
-   klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
+   enc = GST_AUDIO_ENCODER (gst_pad_get_parent (pad));
+   klass = GST_AUDIO_ENCODER_GET_CLASS (enc);
  
    GST_DEBUG_OBJECT (enc, "received event %d, %s", GST_EVENT_TYPE (event),
        GST_EVENT_TYPE_NAME (event));
      handled = klass->event (enc, event);
  
    if (!handled)
-     handled = gst_base_audio_encoder_sink_eventfunc (enc, event);
+     handled = gst_audio_encoder_sink_eventfunc (enc, event);
  
    if (!handled)
      ret = gst_pad_event_default (pad, event);
  }
  
  static gboolean
- gst_base_audio_encoder_sink_query (GstPad * pad, GstQuery * query)
+ gst_audio_encoder_sink_query (GstPad * pad, GstQuery * query)
  {
    gboolean res = TRUE;
-   GstBaseAudioEncoder *enc;
+   GstAudioEncoder *enc;
  
-   enc = GST_BASE_AUDIO_ENCODER (gst_pad_get_parent (pad));
+   enc = GST_AUDIO_ENCODER (gst_pad_get_parent (pad));
  
    switch (GST_QUERY_TYPE (query)) {
      case GST_QUERY_FORMATS:
@@@ -1267,9 -1255,9 +1258,9 @@@ error
  }
  
  static const GstQueryType *
- gst_base_audio_encoder_get_query_types (GstPad * pad)
+ gst_audio_encoder_get_query_types (GstPad * pad)
  {
-   static const GstQueryType gst_base_audio_encoder_src_query_types[] = {
+   static const GstQueryType gst_audio_encoder_src_query_types[] = {
      GST_QUERY_POSITION,
      GST_QUERY_DURATION,
      GST_QUERY_CONVERT,
      0
    };
  
-   return gst_base_audio_encoder_src_query_types;
+   return gst_audio_encoder_src_query_types;
  }
  
  /*
-  * gst_base_audio_encoded_audio_convert:
+  * gst_audio_encoded_audio_convert:
   * @fmt: audio format of the encoded audio
   * @bytes: number of encoded bytes
   * @samples: number of encoded samples
   *
   * Since: 0.10.36
   */
- /* FIXME: make gst_base_audio_encoded_audio_convert() public? */
+ /* FIXME: make gst_audio_encoded_audio_convert() public? */
  static gboolean
- gst_base_audio_encoded_audio_convert (GstAudioInfo * fmt,
+ gst_audio_encoded_audio_convert (GstAudioInfo * fmt,
      gint64 bytes, gint64 samples, GstFormat src_format,
      gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
  {
@@@ -1358,13 -1346,13 +1349,13 @@@ exit
   * segment stuff etc at all
   * Supposedly that's backward compatibility ... */
  static gboolean
- gst_base_audio_encoder_src_query (GstPad * pad, GstQuery * query)
+ gst_audio_encoder_src_query (GstPad * pad, GstQuery * query)
  {
-   GstBaseAudioEncoder *enc;
+   GstAudioEncoder *enc;
    GstPad *peerpad;
    gboolean res = FALSE;
  
-   enc = GST_BASE_AUDIO_ENCODER (GST_PAD_PARENT (pad));
+   enc = GST_AUDIO_ENCODER (GST_PAD_PARENT (pad));
    peerpad = gst_pad_get_peer (GST_PAD (enc->sinkpad));
  
    GST_LOG_OBJECT (enc, "handling query: %" GST_PTR_FORMAT, query);
  
        gst_query_parse_position (query, &req_fmt, NULL);
        fmt = GST_FORMAT_TIME;
 -      if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
 +      if (!(res = gst_pad_query_position (peerpad, fmt, &pos)))
          break;
  
 -      if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val))) {
 +      if ((res = gst_pad_query_convert (peerpad, fmt, pos, req_fmt, &val))) {
          gst_query_set_position (query, req_fmt, val);
        }
        break;
  
        gst_query_parse_duration (query, &req_fmt, NULL);
        fmt = GST_FORMAT_TIME;
 -      if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
 +      if (!(res = gst_pad_query_duration (peerpad, fmt, &dur)))
          break;
  
 -      if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
 +      if ((res = gst_pad_query_convert (peerpad, fmt, dur, req_fmt, &val))) {
          gst_query_set_duration (query, req_fmt, val);
        }
        break;
        gint64 src_val, dest_val;
  
        gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
-       if (!(res = gst_base_audio_encoded_audio_convert (&enc->priv->ctx.info,
+       if (!(res = gst_audio_encoded_audio_convert (&enc->priv->ctx.info,
                    enc->priv->bytes_out, enc->priv->samples_in, src_fmt, src_val,
                    &dest_fmt, &dest_val)))
          break;
  }
  
  static void
- gst_base_audio_encoder_set_property (GObject * object, guint prop_id,
+ gst_audio_encoder_set_property (GObject * object, guint prop_id,
      const GValue * value, GParamSpec * pspec)
  {
-   GstBaseAudioEncoder *enc;
+   GstAudioEncoder *enc;
  
-   enc = GST_BASE_AUDIO_ENCODER (object);
+   enc = GST_AUDIO_ENCODER (object);
  
    switch (prop_id) {
      case PROP_PERFECT_TS:
        if (enc->priv->granule && !g_value_get_boolean (value))
-         GST_WARNING_OBJECT (enc, "perfect-ts can not be set FALSE");
+         GST_WARNING_OBJECT (enc, "perfect-timestamp can not be set FALSE "
+             "while granule handling is enabled");
        else
          enc->priv->perfect_ts = g_value_get_boolean (value);
        break;
  }
  
  static void
- gst_base_audio_encoder_get_property (GObject * object, guint prop_id,
+ gst_audio_encoder_get_property (GObject * object, guint prop_id,
      GValue * value, GParamSpec * pspec)
  {
-   GstBaseAudioEncoder *enc;
+   GstAudioEncoder *enc;
  
-   enc = GST_BASE_AUDIO_ENCODER (object);
+   enc = GST_AUDIO_ENCODER (object);
  
    switch (prop_id) {
      case PROP_PERFECT_TS:
  }
  
  static gboolean
- gst_base_audio_encoder_activate (GstBaseAudioEncoder * enc, gboolean active)
+ gst_audio_encoder_activate (GstAudioEncoder * enc, gboolean active)
  {
-   GstBaseAudioEncoderClass *klass;
+   GstAudioEncoderClass *klass;
    gboolean result = FALSE;
  
-   klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
+   klass = GST_AUDIO_ENCODER_GET_CLASS (enc);
  
    g_return_val_if_fail (!enc->priv->granule || enc->priv->perfect_ts, FALSE);
  
        result = klass->stop (enc);
  
      /* clean up */
-     gst_base_audio_encoder_reset (enc, TRUE);
+     gst_audio_encoder_reset (enc, TRUE);
    }
    GST_DEBUG_OBJECT (enc, "activate return: %d", result);
    return result;
  
  
  static gboolean
- gst_base_audio_encoder_sink_activate_push (GstPad * pad, gboolean active)
+ gst_audio_encoder_sink_activate_push (GstPad * pad, gboolean active)
  {
    gboolean result = TRUE;
-   GstBaseAudioEncoder *enc;
+   GstAudioEncoder *enc;
  
-   enc = GST_BASE_AUDIO_ENCODER (gst_pad_get_parent (pad));
+   enc = GST_AUDIO_ENCODER (gst_pad_get_parent (pad));
  
    GST_DEBUG_OBJECT (enc, "sink activate push %d", active);
  
-   result = gst_base_audio_encoder_activate (enc, active);
+   result = gst_audio_encoder_activate (enc, active);
  
    if (result)
      enc->priv->active = active;
  }
  
  /**
-  * gst_base_audio_encoder_get_audio_info:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_get_audio_info:
+  * @enc: a #GstAudioEncoder
   *
   * Returns: a #GstAudioInfo describing the input audio format
   *
   * Since: 0.10.36
   */
  GstAudioInfo *
- gst_base_audio_encoder_get_audio_info (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_get_audio_info (GstAudioEncoder * enc)
  {
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), NULL);
+   g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), NULL);
  
    return &enc->priv->ctx.info;
  }
  
  /**
-  * gst_base_audio_encoder_set_frame_samples:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_set_frame_samples:
+  * @enc: a #GstAudioEncoder
   * @num: number of samples per frame
   *
   * Sets number of samples (per channel) subclass needs to be handed,
   * Since: 0.10.36
   */
  void
- gst_base_audio_encoder_set_frame_samples (GstBaseAudioEncoder * enc, gint num)
+ gst_audio_encoder_set_frame_samples (GstAudioEncoder * enc, gint num)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
  
    enc->priv->ctx.frame_samples = num;
  }
  
  /**
-  * gst_base_audio_encoder_get_frame_samples:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_get_frame_samples:
+  * @enc: a #GstAudioEncoder
   *
   * Returns: currently requested samples per frame
   *
   * Since: 0.10.36
   */
  gint
- gst_base_audio_encoder_get_frame_samples (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_get_frame_samples (GstAudioEncoder * enc)
  {
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), 0);
+   g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), 0);
  
    return enc->priv->ctx.frame_samples;
  }
  
  /**
-  * gst_base_audio_encoder_set_frame_max:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_set_frame_max:
+  * @enc: a #GstAudioEncoder
   * @num: number of frames
   *
   * Sets max number of frames accepted at once (assumed minimally 1)
   * Since: 0.10.36
   */
  void
- gst_base_audio_encoder_set_frame_max (GstBaseAudioEncoder * enc, gint num)
+ gst_audio_encoder_set_frame_max (GstAudioEncoder * enc, gint num)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
  
    enc->priv->ctx.frame_max = num;
  }
  
  /**
-  * gst_base_audio_encoder_get_frame_max:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_get_frame_max:
+  * @enc: a #GstAudioEncoder
   *
   * Returns: currently configured maximum handled frames
   *
   * Since: 0.10.36
   */
  gint
- gst_base_audio_encoder_get_frame_max (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_get_frame_max (GstAudioEncoder * enc)
  {
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), 0);
+   g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), 0);
  
    return enc->priv->ctx.frame_max;
  }
  
  /**
-  * gst_base_audio_encoder_set_lookahead:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_set_lookahead:
+  * @enc: a #GstAudioEncoder
   * @num: lookahead
   *
   * Sets encoder lookahead (in units of input rate samples)
   * Since: 0.10.36
   */
  void
- gst_base_audio_encoder_set_lookahead (GstBaseAudioEncoder * enc, gint num)
+ gst_audio_encoder_set_lookahead (GstAudioEncoder * enc, gint num)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
  
    enc->priv->ctx.lookahead = num;
  }
  
  /**
-  * gst_base_audio_encoder_get_lookahead:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_get_lookahead:
+  * @enc: a #GstAudioEncoder
   *
   * Returns: currently configured encoder lookahead
   */
  gint
- gst_base_audio_encoder_get_lookahead (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_get_lookahead (GstAudioEncoder * enc)
  {
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), 0);
+   g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), 0);
  
    return enc->priv->ctx.lookahead;
  }
  
  /**
-  * gst_base_audio_encoder_set_latency:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_set_latency:
+  * @enc: a #GstAudioEncoder
   * @min: minimum latency
   * @max: maximum latency
   *
   * Since: 0.10.36
   */
  void
- gst_base_audio_encoder_set_latency (GstBaseAudioEncoder * enc,
+ gst_audio_encoder_set_latency (GstAudioEncoder * enc,
      GstClockTime min, GstClockTime max)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
  
    GST_OBJECT_LOCK (enc);
    enc->priv->ctx.min_latency = min;
  }
  
  /**
-  * gst_base_audio_encoder_get_latency:
-  * @enc: a #GstBaseAudioEncoder
-  * @min: a pointer to storage to hold minimum latency
-  * @max: a pointer to storage to hold maximum latency
+  * gst_audio_encoder_get_latency:
+  * @enc: a #GstAudioEncoder
+  * @min: (out) (allow-none): a pointer to storage to hold minimum latency
+  * @max: (out) (allow-none): a pointer to storage to hold maximum latency
   *
-  * Returns currently configured latency.
+  * Sets the variables pointed to by @min and @max to the currently configured
+  * latency.
   *
   * Since: 0.10.36
   */
  void
- gst_base_audio_encoder_get_latency (GstBaseAudioEncoder * enc,
+ gst_audio_encoder_get_latency (GstAudioEncoder * enc,
      GstClockTime * min, GstClockTime * max)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
  
    GST_OBJECT_LOCK (enc);
    if (min)
  }
  
  /**
-  * gst_base_audio_encoder_set_mark_granule:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_set_mark_granule:
+  * @enc: a #GstAudioEncoder
   * @enabled: new state
   *
   * Enable or disable encoder granule handling.
   * Since: 0.10.36
   */
  void
- gst_base_audio_encoder_set_mark_granule (GstBaseAudioEncoder * enc,
-     gboolean enabled)
+ gst_audio_encoder_set_mark_granule (GstAudioEncoder * enc, gboolean enabled)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
  
    GST_LOG_OBJECT (enc, "enabled: %d", enabled);
  
  }
  
  /**
-  * gst_base_audio_encoder_get_mark_granule:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_get_mark_granule:
+  * @enc: a #GstAudioEncoder
   *
   * Queries if the encoder will handle granule marking.
   *
   * Since: 0.10.36
   */
  gboolean
- gst_base_audio_encoder_get_mark_granule (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_get_mark_granule (GstAudioEncoder * enc)
  {
    gboolean result;
  
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), FALSE);
+   g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), FALSE);
  
    GST_OBJECT_LOCK (enc);
    result = enc->priv->granule;
  }
  
  /**
-  * gst_base_audio_encoder_set_perfect_timestamp:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_set_perfect_timestamp:
+  * @enc: a #GstAudioEncoder
   * @enabled: new state
   *
   * Enable or disable encoder perfect output timestamp preference.
   * Since: 0.10.36
   */
  void
- gst_base_audio_encoder_set_perfect_timestamp (GstBaseAudioEncoder * enc,
+ gst_audio_encoder_set_perfect_timestamp (GstAudioEncoder * enc,
      gboolean enabled)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
  
    GST_LOG_OBJECT (enc, "enabled: %d", enabled);
  
  }
  
  /**
-  * gst_base_audio_encoder_get_perfect_timestamp:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_get_perfect_timestamp:
+  * @enc: a #GstAudioEncoder
   *
   * Queries encoder perfect timestamp behaviour.
   *
   * Since: 0.10.36
   */
  gboolean
- gst_base_audio_encoder_get_perfect_timestamp (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_get_perfect_timestamp (GstAudioEncoder * enc)
  {
    gboolean result;
  
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), FALSE);
+   g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), FALSE);
  
    GST_OBJECT_LOCK (enc);
    result = enc->priv->perfect_ts;
  }
  
  /**
-  * gst_base_audio_encoder_set_hard_sync:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_set_hard_sync:
+  * @enc: a #GstAudioEncoder
   * @enabled: new state
   *
   * Sets encoder hard resync handling.
   * Since: 0.10.36
   */
  void
- gst_base_audio_encoder_set_hard_resync (GstBaseAudioEncoder * enc,
-     gboolean enabled)
+ gst_audio_encoder_set_hard_resync (GstAudioEncoder * enc, gboolean enabled)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
  
    GST_LOG_OBJECT (enc, "enabled: %d", enabled);
  
  }
  
  /**
-  * gst_base_audio_encoder_get_hard_sync:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_get_hard_sync:
+  * @enc: a #GstAudioEncoder
   *
   * Queries encoder's hard resync setting.
   *
   * Since: 0.10.36
   */
  gboolean
- gst_base_audio_encoder_get_hard_resync (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_get_hard_resync (GstAudioEncoder * enc)
  {
    gboolean result;
  
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), FALSE);
+   g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), FALSE);
  
    GST_OBJECT_LOCK (enc);
    result = enc->priv->hard_resync;
  }
  
  /**
-  * gst_base_audio_encoder_set_tolerance:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_set_tolerance:
+  * @enc: a #GstAudioEncoder
   * @tolerance: new tolerance
   *
   * Configures encoder audio jitter tolerance threshold.
   * Since: 0.10.36
   */
  void
- gst_base_audio_encoder_set_tolerance (GstBaseAudioEncoder * enc,
-     gint64 tolerance)
+ gst_audio_encoder_set_tolerance (GstAudioEncoder * enc, gint64 tolerance)
  {
-   g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
+   g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
  
    GST_OBJECT_LOCK (enc);
    enc->priv->tolerance = tolerance;
  }
  
  /**
-  * gst_base_audio_encoder_get_tolerance:
-  * @enc: a #GstBaseAudioEncoder
+  * gst_audio_encoder_get_tolerance:
+  * @enc: a #GstAudioEncoder
   *
   * Queries current audio jitter tolerance threshold.
   *
   * Since: 0.10.36
   */
  gint64
- gst_base_audio_encoder_get_tolerance (GstBaseAudioEncoder * enc)
+ gst_audio_encoder_get_tolerance (GstAudioEncoder * enc)
  {
    gint64 result;
  
-   g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), 0);
+   g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), 0);
  
    GST_OBJECT_LOCK (enc);
    result = enc->priv->tolerance;
index 0000000,a8ff018..1a8c5af
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,243 +1,243 @@@
 -  GstCaps *     (*getcaps)            (GstAudioEncoder *enc);
+ /* GStreamer
+  * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>.
+  * Copyright (C) 2011 Nokia Corporation. All rights reserved.
+  *   Contact: Stefan Kost <stefan.kost@nokia.com>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Library General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Library General Public License for more details.
+  *
+  * You should have received a copy of the GNU Library General Public
+  * License along with this library; if not, write to the
+  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  * Boston, MA 02111-1307, USA.
+  */
+ #ifndef __GST_AUDIO_ENCODER_H__
+ #define __GST_AUDIO_ENCODER_H__
+ #ifndef GST_USE_UNSTABLE_API
+ #warning "GstAudioEncoder is unstable API and may change in future."
+ #warning "You can define GST_USE_UNSTABLE_API to avoid this warning."
+ #endif
+ #include <gst/gst.h>
+ #include <gst/audio/audio.h>
+ G_BEGIN_DECLS
+ #define GST_TYPE_AUDIO_ENCODER                   (gst_audio_encoder_get_type())
+ #define GST_AUDIO_ENCODER(obj)                   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_ENCODER,GstAudioEncoder))
+ #define GST_AUDIO_ENCODER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_ENCODER,GstAudioEncoderClass))
+ #define GST_AUDIO_ENCODER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_AUDIO_ENCODER,GstAudioEncoderClass))
+ #define GST_IS_AUDIO_ENCODER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_ENCODER))
+ #define GST_IS_AUDIO_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_ENCODER))
+ #define GST_AUDIO_ENCODER_CAST(obj)   ((GstAudioEncoder *)(obj))
+ /**
+  * GST_AUDIO_ENCODER_SINK_NAME:
+  *
+  * the name of the templates for the sink pad
+  *
+  * Since: 0.10.36
+  */
+ #define GST_AUDIO_ENCODER_SINK_NAME   "sink"
+ /**
+  * GST_AUDIO_ENCODER_SRC_NAME:
+  *
+  * the name of the templates for the source pad
+  *
+  * Since: 0.10.36
+  */
+ #define GST_AUDIO_ENCODER_SRC_NAME            "src"
+ /**
+  * GST_AUDIO_ENCODER_SRC_PAD:
+  * @obj: base parse instance
+  *
+  * Gives the pointer to the source #GstPad object of the element.
+  *
+  * Since: 0.10.36
+  */
+ #define GST_AUDIO_ENCODER_SRC_PAD(obj)        (GST_AUDIO_ENCODER_CAST (obj)->srcpad)
+ /**
+  * GST_AUDIO_ENCODER_SINK_PAD:
+  * @obj: base parse instance
+  *
+  * Gives the pointer to the sink #GstPad object of the element.
+  *
+  * Since: 0.10.36
+  */
+ #define GST_AUDIO_ENCODER_SINK_PAD(obj)       (GST_AUDIO_ENCODER_CAST (obj)->sinkpad)
+ /**
+  * GST_AUDIO_ENCODER_SEGMENT:
+  * @obj: base parse instance
+  *
+  * Gives the segment of the element.
+  *
+  * Since: 0.10.36
+  */
+ #define GST_AUDIO_ENCODER_SEGMENT(obj)     (GST_AUDIO_ENCODER_CAST (obj)->segment)
+ typedef struct _GstAudioEncoder GstAudioEncoder;
+ typedef struct _GstAudioEncoderClass GstAudioEncoderClass;
+ typedef struct _GstAudioEncoderPrivate GstAudioEncoderPrivate;
+ /**
+  * GstAudioEncoder:
+  *
+  * The opaque #GstAudioEncoder data structure.
+  *
+  * Since: 0.10.36
+  */
+ struct _GstAudioEncoder {
+   GstElement     element;
+   /*< protected >*/
+   /* source and sink pads */
+   GstPad         *sinkpad;
+   GstPad         *srcpad;
+   /* MT-protected (with STREAM_LOCK) */
+   GstSegment      segment;
+   /*< private >*/
+   GstAudioEncoderPrivate *priv;
+   gpointer       _gst_reserved[GST_PADDING_LARGE];
+ };
+ /**
+  * GstAudioEncoderClass:
+  * @element_class:  The parent class structure
+  * @start:          Optional.
+  *                  Called when the element starts processing.
+  *                  Allows opening external resources.
+  * @stop:           Optional.
+  *                  Called when the element stops processing.
+  *                  Allows closing external resources.
+  * @set_format:     Notifies subclass of incoming data format.
+  *                  GstAudioInfo contains the format according to provided caps.
+  * @handle_frame:   Provides input samples (or NULL to clear any remaining data)
+  *                  according to directions as configured by the subclass
+  *                  using the API.  Input data ref management is performed
+  *                  by base class, subclass should not care or intervene.
+  * @flush:          Optional.
+  *                  Instructs subclass to clear any codec caches and discard
+  *                  any pending samples and not yet returned encoded data.
+  * @event:          Optional.
+  *                  Event handler on the sink pad. This function should return
+  *                  TRUE if the event was handled and should be discarded
+  *                  (i.e. not unref'ed).
+  * @pre_push:       Optional.
+  *                  Called just prior to pushing (encoded data) buffer downstream.
+  *                  Subclass has full discretionary access to buffer,
+  *                  and a not OK flow return will abort downstream pushing.
+  * @getcaps:        Optional.
+  *                  Allows for a custom sink getcaps implementation (e.g.
+  *                  for multichannel input specification).  If not implemented,
+  *                  default returns gst_audio_encoder_proxy_getcaps
+  *                  applied to sink template caps.
+  *
+  * Subclasses can override any of the available virtual methods or not, as
+  * needed. At minimum @set_format and @handle_frame needs to be overridden.
+  *
+  * Since: 0.10.36
+  */
+ struct _GstAudioEncoderClass {
+   GstElementClass element_class;
+   /*< public >*/
+   /* virtual methods for subclasses */
+   gboolean      (*start)              (GstAudioEncoder *enc);
+   gboolean      (*stop)               (GstAudioEncoder *enc);
+   gboolean      (*set_format)         (GstAudioEncoder *enc,
+                                        GstAudioInfo        *info);
+   GstFlowReturn (*handle_frame)       (GstAudioEncoder *enc,
+                                        GstBuffer *buffer);
+   void          (*flush)              (GstAudioEncoder *enc);
+   GstFlowReturn (*pre_push)           (GstAudioEncoder *enc,
+                                        GstBuffer **buffer);
+   gboolean      (*event)              (GstAudioEncoder *enc,
+                                        GstEvent *event);
++  GstCaps *     (*getcaps)            (GstAudioEncoder *enc, GstCaps *filter);
+   /*< private >*/
+   gpointer       _gst_reserved[GST_PADDING_LARGE];
+ };
+ GType           gst_audio_encoder_get_type         (void);
+ GstFlowReturn   gst_audio_encoder_finish_frame (GstAudioEncoder * enc,
+                                                 GstBuffer       * buffer,
+                                                 gint              samples);
+ GstCaps *       gst_audio_encoder_proxy_getcaps (GstAudioEncoder * enc,
+                                                  GstCaps         * caps);
+ /* context parameters */
+ GstAudioInfo  * gst_audio_encoder_get_audio_info (GstAudioEncoder * enc);
+ gint            gst_audio_encoder_get_frame_samples (GstAudioEncoder * enc);
+ void            gst_audio_encoder_set_frame_samples (GstAudioEncoder * enc, gint num);
+ gint            gst_audio_encoder_get_frame_max (GstAudioEncoder * enc);
+ void            gst_audio_encoder_set_frame_max (GstAudioEncoder * enc, gint num);
+ gint            gst_audio_encoder_get_lookahead (GstAudioEncoder * enc);
+ void            gst_audio_encoder_set_lookahead (GstAudioEncoder * enc, gint num);
+ void            gst_audio_encoder_get_latency (GstAudioEncoder * enc,
+                                                GstClockTime    * min,
+                                                GstClockTime    * max);
+ void            gst_audio_encoder_set_latency (GstAudioEncoder * enc,
+                                                GstClockTime      min,
+                                                GstClockTime      max);
+ /* object properties */
+ void            gst_audio_encoder_set_mark_granule (GstAudioEncoder * enc,
+                                                     gboolean enabled);
+ gboolean        gst_audio_encoder_get_mark_granule (GstAudioEncoder * enc);
+ void            gst_audio_encoder_set_perfect_timestamp (GstAudioEncoder * enc,
+                                                          gboolean          enabled);
+ gboolean        gst_audio_encoder_get_perfect_timestamp (GstAudioEncoder * enc);
+ void            gst_audio_encoder_set_hard_resync (GstAudioEncoder * enc,
+                                                    gboolean          enabled);
+ gboolean        gst_audio_encoder_get_hard_resync (GstAudioEncoder * enc);
+ void            gst_audio_encoder_set_tolerance (GstAudioEncoder * enc,
+                                                  gint64            tolerance);
+ gint64          gst_audio_encoder_get_tolerance (GstAudioEncoder * enc);
+ G_END_DECLS
+ #endif /* __GST_AUDIO_ENCODER_H__ */
index 0000000,0000000..9834715
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,262 @@@
++/* GStreamer
++ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
++ * Copyright (C) <2003> David Schleef <ds@schleef.org>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * This file was (probably) generated from
++ * $Id$
++ * and
++ * $Id$
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <gst/gst.h>
++#include <gst/audio/audio.h>
++#include <gst/audio/gstaudiofilter.h>
++#include <string.h>
++
++GST_DEBUG_CATEGORY_STATIC (audio_filter_template_debug);
++#define GST_CAT_DEFAULT audio_filter_template_debug
++
++static const GstElementDetails audio_filter_template_details =
++GST_ELEMENT_DETAILS ("Audio filter template",
++    "Filter/Effect/Audio",
++    "Filters audio",
++    "David Schleef <ds@schleef.org>");
++
++typedef struct _GstAudioFilterTemplate GstAudioFilterTemplate;
++typedef struct _GstAudioFilterTemplateClass GstAudioFilterTemplateClass;
++
++#define GST_TYPE_AUDIO_FILTER_TEMPLATE \
++  (gst_audio_filter_template_get_type())
++#define GST_AUDIO_FILTER_TEMPLATE(obj) \
++  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_FILTER_TEMPLATE,GstAudioFilterTemplate))
++#define GST_AUDIO_FILTER_TEMPLATE_CLASS(klass) \
++  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_FILTER_TEMPLATE,GstAudioFilterTemplateClass))
++#define GST_IS_AUDIO_FILTER_TEMPLATE(obj) \
++  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_FILTER_TEMPLATE))
++#define GST_IS_AUDIO_FILTER_TEMPLATE_CLASS(klass) \
++  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_FILTER_TEMPLATE))
++
++struct _GstAudioFilterTemplate
++{
++  GstAudioFilter audiofilter;
++};
++
++struct _GstAudioFilterTemplateClass
++{
++  GstAudioFilterClass parent_class;
++};
++
++
++enum
++{
++  /* FILL ME */
++  LAST_SIGNAL
++};
++
++enum
++{
++  ARG_0
++      /* FILL ME */
++};
++
++GST_BOILERPLATE (GstAudioFilterTemplate, gst_audio_filter_template,
++    GstAudioFilter, GST_TYPE_AUDIO_FILTER);
++
++static void gst_audio_filter_template_set_property (GObject * object,
++    guint prop_id, const GValue * value, GParamSpec * pspec);
++static void gst_audio_filter_template_get_property (GObject * object,
++    guint prop_id, GValue * value, GParamSpec * pspec);
++
++static gboolean gst_audio_filter_template_setup (GstAudioFilter * filter,
++    GstRingBufferSpec * spec);
++static GstFlowReturn gst_audio_filter_template_filter (GstBaseTransform * bt,
++    GstBuffer * outbuf, GstBuffer * inbuf);
++static GstFlowReturn
++gst_audio_filter_template_filter_inplace (GstBaseTransform * base_transform,
++    GstBuffer * buf);
++
++#define ALLOWED_CAPS_STRING \
++    GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS
++
++static void
++gst_audio_filter_template_base_init (gpointer g_class)
++{
++  GstAudioFilterTemplateClass *klass = (GstAudioFilterTemplateClass *) g_class;
++  GstAudioFilterClass *audiofilter_class = GST_AUDIO_FILTER_CLASS (g_class);
++  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
++  GstCaps *caps;
++
++  gst_element_class_set_details (element_class, &audio_filter_template_details);
++
++  caps = gst_caps_from_string (ALLOWED_CAPS_STRING);
++  gst_audio_filter_class_add_pad_templates (audiofilter_class, caps);
++  gst_caps_unref (caps);
++}
++
++static void
++gst_audio_filter_template_class_init (GstAudioFilterTemplateClass * klass)
++{
++  GObjectClass *gobject_class;
++  GstBaseTransformClass *btrans_class;
++  GstAudioFilterClass *audio_filter_class;
++
++  gobject_class = (GObjectClass *) klass;
++  btrans_class = (GstBaseTransformClass *) klass;
++  audio_filter_class = (GstAudioFilterClass *) klass;
++
++#if 0
++  g_object_class_install_property (gobject_class, ARG_METHOD,
++      g_param_spec_enum ("method", "method", "method",
++          GST_TYPE_AUDIOTEMPLATE_METHOD, GST_AUDIOTEMPLATE_METHOD_1,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++#endif
++
++  gobject_class->set_property = gst_audio_filter_template_set_property;
++  gobject_class->get_property = gst_audio_filter_template_get_property;
++
++  /* this function will be called whenever the format changes */
++  audio_filter_class->setup = gst_audio_filter_template_setup;
++
++  /* here you set up functions to process data (either in place, or from
++   * one input buffer to another output buffer); only one is required */
++  btrans_class->transform = gst_audio_filter_template_filter;
++  btrans_class->transform_ip = gst_audio_filter_template_filter_inplace;
++}
++
++static void
++gst_audio_filter_template_init (GstAudioFilterTemplate * audio_filter_template,
++    GstAudioFilterTemplateClass * g_class)
++{
++  GST_DEBUG ("init");
++
++  /* do stuff if you need to */
++}
++
++static void
++gst_audio_filter_template_set_property (GObject * object, guint prop_id,
++    const GValue * value, GParamSpec * pspec)
++{
++  GstAudioFilterTemplate *filter;
++
++  filter = GST_AUDIO_FILTER_TEMPLATE (object);
++
++  GST_DEBUG ("set  property %u", prop_id);
++
++  GST_OBJECT_LOCK (filter);
++  switch (prop_id) {
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++  }
++  GST_OBJECT_UNLOCK (filter);
++}
++
++static void
++gst_audio_filter_template_get_property (GObject * object, guint prop_id,
++    GValue * value, GParamSpec * pspec)
++{
++  GstAudioFilterTemplate *filter;
++
++  filter = GST_AUDIO_FILTER_TEMPLATE (object);
++
++  GST_DEBUG ("get  property %u", prop_id);
++
++  GST_OBJECT_LOCK (filter);
++  switch (prop_id) {
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++  }
++  GST_OBJECT_UNLOCK (filter);
++}
++
++static gboolean
++gst_audio_filter_template_setup (GstAudioFilter * filter,
++    GstRingBufferSpec * spec)
++{
++  GstAudioFilterTemplate *audio_filter_template;
++
++  audio_filter_template = GST_AUDIO_FILTER_TEMPLATE (filter);
++
++  /* if any setup needs to be done, do it here */
++
++  return TRUE;                  /* it's all good */
++}
++
++/* You may choose to implement either a copying filter or an
++ * in-place filter (or both).  Implementing only one will give
++ * full functionality, however, implementing both will cause
++ * audiofilter to use the optimal function in every situation,
++ * with a minimum of memory copies. */
++
++static GstFlowReturn
++gst_audio_filter_template_filter (GstBaseTransform * base_transform,
++    GstBuffer * inbuf, GstBuffer * outbuf)
++{
++  GstAudioFilterTemplate *audio_filter_template;
++  GstAudioFilter *audiofilter;
++
++  audiofilter = GST_AUDIO_FILTER (base_transform);
++  audio_filter_template = GST_AUDIO_FILTER_TEMPLATE (base_transform);
++
++  /* do something interesting here.  This simply copies the source
++   * to the destination. */
++
++  memcpy (GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf),
++      GST_BUFFER_SIZE (inbuf));
++
++  return GST_FLOW_OK;
++}
++
++static GstFlowReturn
++gst_audio_filter_template_filter_inplace (GstBaseTransform * base_transform,
++    GstBuffer * buf)
++{
++  GstAudioFilterTemplate *audio_filter_template;
++  GstAudioFilter *audiofilter;
++
++  audiofilter = GST_AUDIO_FILTER (base_transform);
++  audio_filter_template = GST_AUDIO_FILTER_TEMPLATE (base_transform);
++
++  /* do something interesting here.  This simply copies the source
++   * to the destination. */
++
++  return GST_FLOW_OK;
++}
++
++static gboolean
++plugin_init (GstPlugin * plugin)
++{
++  GST_DEBUG_CATEGORY_INIT (audio_filter_template_debug, "audiofilterexample",
++      0, "audiofilterexample");
++
++  return gst_element_register (plugin, "audiofilterexample", GST_RANK_NONE,
++      GST_TYPE_AUDIO_FILTER_TEMPLATE);
++}
++
++GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
++    GST_VERSION_MINOR,
++    "gstaudio_filter_template",
++    "Audio filter template",
++    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
index 0000000,0000000..716df04
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,224 @@@
++/* GStreamer RTSP extension
++ * Copyright (C) 2007 Wim Taymans <wim.taymans@gmail.com>
++ *
++ * gstrtspextension.c: RTSP extension mechanism
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/**
++ * SECTION:gstrtspextension
++ * @short_description: Interface for extending RTSP protocols
++ *
++ * <refsect2>
++ * <para>
++ *  This interface is implemented e.g. by the Windows Media Streaming RTSP
++ *  exentension (rtspwms) and the RealMedia RTSP extension (rtspreal).
++ * </para>
++ * </refsect2>
++ *
++ * Last reviewed on 2007-07-25 (0.10.14)
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include "gstrtsp-marshal.h"
++#include "gstrtsp-enumtypes.h"
++#include "gstrtspextension.h"
++
++static void gst_rtsp_extension_iface_init (GstRTSPExtension * iface);
++
++enum
++{
++  SIGNAL_SEND,
++  LAST_SIGNAL
++};
++
++static guint gst_rtsp_extension_signals[LAST_SIGNAL] = { 0 };
++
++GType
++gst_rtsp_extension_get_type (void)
++{
++  static GType gst_rtsp_extension_type = 0;
++
++  if (!gst_rtsp_extension_type) {
++    static const GTypeInfo gst_rtsp_extension_info = {
++      sizeof (GstRTSPExtensionInterface),
++      (GBaseInitFunc) gst_rtsp_extension_iface_init,
++      NULL,
++      NULL,
++      NULL,
++      NULL,
++      0,
++      0,
++      NULL,
++    };
++
++    gst_rtsp_extension_type = g_type_register_static (G_TYPE_INTERFACE,
++        "GstRTSPExtension", &gst_rtsp_extension_info, 0);
++  }
++  return gst_rtsp_extension_type;
++}
++
++static void
++gst_rtsp_extension_iface_init (GstRTSPExtension * iface)
++{
++  static gboolean initialized = FALSE;
++
++  if (!initialized) {
++    gst_rtsp_extension_signals[SIGNAL_SEND] =
++        g_signal_new ("send", G_TYPE_FROM_CLASS (iface),
++        G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPExtensionInterface,
++            send), NULL, NULL, gst_rtsp_marshal_ENUM__POINTER_POINTER,
++        GST_TYPE_RTSP_RESULT, 2, G_TYPE_POINTER, G_TYPE_POINTER);
++    initialized = TRUE;
++  }
++}
++
++gboolean
++gst_rtsp_extension_detect_server (GstRTSPExtension * ext, GstRTSPMessage * resp)
++{
++  GstRTSPExtensionInterface *iface;
++  gboolean res = TRUE;
++
++  iface = GST_RTSP_EXTENSION_GET_IFACE (ext);
++  if (iface->detect_server)
++    res = iface->detect_server (ext, resp);
++
++  return res;
++}
++
++GstRTSPResult
++gst_rtsp_extension_before_send (GstRTSPExtension * ext, GstRTSPMessage * req)
++{
++  GstRTSPExtensionInterface *iface;
++  GstRTSPResult res = GST_RTSP_OK;
++
++  iface = GST_RTSP_EXTENSION_GET_IFACE (ext);
++  if (iface->before_send)
++    res = iface->before_send (ext, req);
++
++  return res;
++}
++
++GstRTSPResult
++gst_rtsp_extension_after_send (GstRTSPExtension * ext, GstRTSPMessage * req,
++    GstRTSPMessage * resp)
++{
++  GstRTSPExtensionInterface *iface;
++  GstRTSPResult res = GST_RTSP_OK;
++
++  iface = GST_RTSP_EXTENSION_GET_IFACE (ext);
++  if (iface->after_send)
++    res = iface->after_send (ext, req, resp);
++
++  return res;
++}
++
++GstRTSPResult
++gst_rtsp_extension_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
++    GstStructure * s)
++{
++  GstRTSPExtensionInterface *iface;
++  GstRTSPResult res = GST_RTSP_OK;
++
++  iface = GST_RTSP_EXTENSION_GET_IFACE (ext);
++  if (iface->parse_sdp)
++    res = iface->parse_sdp (ext, sdp, s);
++
++  return res;
++}
++
++GstRTSPResult
++gst_rtsp_extension_setup_media (GstRTSPExtension * ext, GstSDPMedia * media)
++{
++  GstRTSPExtensionInterface *iface;
++  GstRTSPResult res = GST_RTSP_OK;
++
++  iface = GST_RTSP_EXTENSION_GET_IFACE (ext);
++  if (iface->setup_media)
++    res = iface->setup_media (ext, media);
++
++  return res;
++}
++
++gboolean
++gst_rtsp_extension_configure_stream (GstRTSPExtension * ext, GstCaps * caps)
++{
++  GstRTSPExtensionInterface *iface;
++  gboolean res = TRUE;
++
++  iface = GST_RTSP_EXTENSION_GET_IFACE (ext);
++  if (iface->configure_stream)
++    res = iface->configure_stream (ext, caps);
++
++  return res;
++}
++
++GstRTSPResult
++gst_rtsp_extension_get_transports (GstRTSPExtension * ext,
++    GstRTSPLowerTrans protocols, gchar ** transport)
++{
++  GstRTSPExtensionInterface *iface;
++  GstRTSPResult res = GST_RTSP_OK;
++
++  iface = GST_RTSP_EXTENSION_GET_IFACE (ext);
++  if (iface->get_transports)
++    res = iface->get_transports (ext, protocols, transport);
++
++  return res;
++}
++
++GstRTSPResult
++gst_rtsp_extension_stream_select (GstRTSPExtension * ext, GstRTSPUrl * url)
++{
++  GstRTSPExtensionInterface *iface;
++  GstRTSPResult res = GST_RTSP_OK;
++
++  iface = GST_RTSP_EXTENSION_GET_IFACE (ext);
++  if (iface->stream_select)
++    res = iface->stream_select (ext, url);
++
++  return res;
++}
++
++GstRTSPResult
++gst_rtsp_extension_receive_request (GstRTSPExtension * ext,
++    GstRTSPMessage * msg)
++{
++  GstRTSPExtensionInterface *iface;
++  GstRTSPResult res = GST_RTSP_ENOTIMPL;
++
++  iface = GST_RTSP_EXTENSION_GET_IFACE (ext);
++  if (iface->receive_request)
++    res = iface->receive_request (ext, msg);
++
++  return res;
++}
++
++GstRTSPResult
++gst_rtsp_extension_send (GstRTSPExtension * ext, GstRTSPMessage * req,
++    GstRTSPMessage * resp)
++{
++  GstRTSPResult res = GST_RTSP_OK;
++
++  g_signal_emit (ext, gst_rtsp_extension_signals[SIGNAL_SEND], 0,
++      req, resp, &res);
++
++  return res;
++}
index 0000000,0000000..8a73bfa
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,61 @@@
++/* GStreamer Audio Process
++ * Copyright (C) 2010 Wim Taymans <wim.taymans@gmail.com>
++ *
++ * gstaudioprocess.h: Audio processing extension
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __GST_AUDIO_PROCESS_H__
++#define __GST_AUDIO_PROCESS_H__
++
++#include <gst/gst.h>
++
++G_BEGIN_DECLS
++
++#define GST_TYPE_AUDIO_PROCESS \
++  (gst_audio_process_get_type ())
++#define GST_AUDIO_PROCESS(obj) \
++  (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUDIO_PROCESS, GstAudioProcess))
++#define GST_IS_AUDIO_PROCESS(obj) \
++  (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUDIO_PROCESS))
++#define GST_AUDIO_PROCESS_GET_IFACE(inst) \
++  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_AUDIO_PROCESS, GstAudioProcessInterface))
++
++typedef struct _GstAudioProcess GstAudioProcess;
++typedef struct _GstAudioProcessInterface GstAudioProcessInterface;
++
++struct _GstAudioProcessInterface {
++  GTypeInterface parent;
++
++  /* vfunctions */
++  gint          (*activate)       (GstAudioProcess *process, gboolean active);
++  gint          (*process)        (GstAudioProcess *process, gpointer src_in, gpointer sink_in,
++                                   gpointer src_out, guint length);
++
++  /*< private >*/
++  gpointer                 _gst_reserved[GST_PADDING];
++};
++
++GType           gst_audio_process_get_type          (void);
++
++/* invoke vfunction on interface */
++gint    gst_audio_process_process   (GstAudioProcess *ext, gpointer src_in, gpointer sink_in,
++                                     gpointer src_out, guint length);
++
++G_END_DECLS
++
++#endif /* __GST_AUDIO_PROCESS_H__ */
index 0000000,0000000..19e9070
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,216 @@@
++/* GStreamer
++ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
++ *                    2005 Wim Taymans <wim@fluendo.com>
++ *
++ * gstaudioringbuffer.c: simple audio ringbuffer base class
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++
++#include <string.h>
++
++#include "gstaudioringbuffer.h"
++
++GST_DEBUG_CATEGORY_STATIC (gst_audio_ring_buffer_debug);
++#define GST_CAT_DEFAULT gst_audio_ring_buffer_debug
++
++static void gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass);
++static void gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer,
++    GstAudioRingBufferClass * klass);
++static void gst_audio_ring_buffer_dispose (GObject * object);
++static void gst_audio_ring_buffer_finalize (GObject * object);
++
++static GstRingBufferClass *ring_parent_class = NULL;
++
++static gboolean gst_audio_ring_buffer_start (GstRingBuffer * buf);
++static gboolean gst_audio_ring_buffer_pause (GstRingBuffer * buf);
++static gboolean gst_audio_ring_buffer_stop (GstRingBuffer * buf);
++static gboolean gst_audio_ring_buffer_activate (GstRingBuffer * buf,
++    gboolean active);
++
++/* ringbuffer abstract base class */
++GType
++gst_audio_ring_buffer_get_type (void)
++{
++  static GType ringbuffer_type = 0;
++
++  if (!ringbuffer_type) {
++    static const GTypeInfo ringbuffer_info = {
++      sizeof (GstAudioRingBufferClass),
++      NULL,
++      NULL,
++      (GClassInitFunc) gst_audio_ring_buffer_class_init,
++      NULL,
++      NULL,
++      sizeof (GstAudioRingBuffer),
++      0,
++      (GInstanceInitFunc) gst_audio_ring_buffer_init,
++      NULL
++    };
++
++    ringbuffer_type =
++        g_type_register_static (GST_TYPE_RING_BUFFER, "GstAudioSinkRingBuffer",
++        &ringbuffer_info, G_TYPE_FLAG_ABSTRACT);
++
++    GST_DEBUG_CATEGORY_INIT (gst_audio_ring_buffer_debug, "audioringbuffer", 0,
++        "audio ringbuffer");
++  }
++  return ringbuffer_type;
++}
++
++static void
++gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass)
++{
++  GObjectClass *gobject_class;
++  GstRingBufferClass *gstringbuffer_class;
++
++  gobject_class = (GObjectClass *) klass;
++  gstringbuffer_class = (GstRingBufferClass *) klass;
++
++  ring_parent_class = g_type_class_peek_parent (klass);
++
++  gobject_class->dispose = gst_audio_ring_buffer_dispose;
++  gobject_class->finalize = gst_audio_ring_buffer_finalize;
++
++  gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_start);
++  gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_pause);
++  gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_start);
++  gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_stop);
++
++  gstringbuffer_class->activate =
++      GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_activate);
++}
++
++static void
++gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer,
++    GstAudioRingBufferClass * g_class)
++{
++}
++
++static void
++gst_audio_ring_buffer_dispose (GObject * object)
++{
++  G_OBJECT_CLASS (ring_parent_class)->dispose (object);
++}
++
++static void
++gst_audio_ring_buffer_finalize (GObject * object)
++{
++  G_OBJECT_CLASS (ring_parent_class)->finalize (object);
++}
++
++static gboolean
++gst_audio_ring_buffer_activate (GstRingBuffer * buf, gboolean active)
++{
++  GstAudioRingBuffer *abuf;
++  gboolean res;
++
++  abuf = GST_AUDIO_RING_BUFFER_CAST (buf);
++
++  GST_OBJECT_UNLOCK (buf);
++  res = gst_ring_buffer_thread_activate (abuf->thread, active);
++  GST_OBJECT_LOCK (buf);
++
++  return res;
++}
++
++gboolean
++gst_audio_ring_buffer_set_thread (GstAudioRingBuffer * buf,
++    GstRingBufferThread * thread)
++{
++  GstRingBufferThread *old;
++
++  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
++
++  old = buf->thread;
++  if (thread)
++    gst_object_ref (thread);
++  buf->thread = thread;
++  if (old)
++    gst_object_unref (old);
++
++  if (thread)
++    gst_ring_buffer_thread_set_ringbuffer (thread, buf);
++
++  return TRUE;
++}
++
++gboolean
++gst_audio_ring_buffer_link (GstAudioRingBuffer * buf1,
++    GstAudioRingBuffer * buf2)
++{
++  buf1->link = buf2;
++  buf2->link = buf1;
++
++  return TRUE;
++}
++
++static gboolean
++gst_audio_ring_buffer_start (GstRingBuffer * buf)
++{
++  GstAudioRingBuffer *abuf;
++
++  abuf = GST_AUDIO_RING_BUFFER_CAST (buf);
++
++  GST_DEBUG_OBJECT (buf, "start, sending signal");
++
++  return gst_ring_buffer_thread_start (abuf->thread);
++}
++
++static gboolean
++gst_audio_ring_buffer_pause (GstRingBuffer * buf)
++{
++  GstAudioRingBuffer *abuf;
++  GstAudioRingBufferClass *cbuf;
++
++  abuf = GST_AUDIO_RING_BUFFER_CAST (buf);
++  cbuf = GST_AUDIO_RING_BUFFER_GET_CLASS (abuf);
++
++  /* unblock any pending writes to the audio device */
++  if (cbuf->reset) {
++    GST_DEBUG_OBJECT (abuf, "reset...");
++    cbuf->reset (abuf);
++    GST_DEBUG_OBJECT (abuf, "reset done");
++  }
++  return TRUE;
++}
++
++static gboolean
++gst_audio_ring_buffer_stop (GstRingBuffer * buf)
++{
++  GstAudioRingBuffer *abuf;
++  GstAudioRingBufferClass *cbuf;
++
++  abuf = GST_AUDIO_RING_BUFFER_CAST (buf);
++  cbuf = GST_AUDIO_RING_BUFFER_GET_CLASS (abuf);
++
++  /* unblock any pending writes to the audio device */
++  if (cbuf->reset) {
++    GST_DEBUG_OBJECT (abuf, "reset...");
++    cbuf->reset (abuf);
++    GST_DEBUG_OBJECT (abuf, "reset done");
++  }
++#if 0
++  if (abuf->running) {
++    GST_DEBUG_OBJECT (sink, "stop, waiting...");
++    GST_AUDIO_RING_BUFFER_WAIT (buf);
++    GST_DEBUG_OBJECT (sink, "stopped");
++  }
++#endif
++
++  return TRUE;
++}
index 0000000,0000000..c643e84
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,98 @@@
++/* GStreamer
++ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
++ *                    2005 Wim Taymans <wim@fluendo.com>
++ *
++ * gstaudioringbuffer.h:
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __GST_AUDIO_RING_BUFFER_H__
++#define __GST_AUDIO_RING_BUFFER_H__
++
++#include <gst/gst.h>
++#include <gst/audio/gstringbuffer.h>
++
++G_BEGIN_DECLS
++
++#define GST_TYPE_AUDIO_RING_BUFFER             (gst_audio_ring_buffer_get_type())
++#define GST_AUDIO_RING_BUFFER(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_RING_BUFFER,GstAudioRingBuffer))
++#define GST_AUDIO_RING_BUFFER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_RING_BUFFER,GstAudioRingBufferClass))
++#define GST_AUDIO_RING_BUFFER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_AUDIO_RING_BUFFER,GstAudioRingBufferClass))
++#define GST_IS_AUDIO_RING_BUFFER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_RING_BUFFER))
++#define GST_IS_AUDIO_RING_BUFFER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_RING_BUFFER))
++#define GST_AUDIO_RING_BUFFER_CAST(obj)        ((GstAudioRingBuffer *)obj)
++
++typedef struct _GstAudioRingBuffer GstAudioRingBuffer;
++typedef struct _GstAudioRingBufferClass GstAudioRingBufferClass;
++
++#include <gst/audio/gstringbufferthread.h>
++
++typedef enum {
++  GST_AUDIO_RING_BUFFER_MODE_UNKNOWN,
++  GST_AUDIO_RING_BUFFER_MODE_PLAYBACK,
++  GST_AUDIO_RING_BUFFER_MODE_CAPTURE
++} GstAudioRingBufferMode;
++/**
++ * GstAudioRingBuffer:
++ *
++ * Opaque #GstAudioRingBuffer.
++ */
++struct _GstAudioRingBuffer {
++  GstRingBuffer       element;
++
++  /*< protected >*/
++  GstAudioRingBufferMode  mode;
++  GstRingBufferThread    *thread;
++
++  GstAudioRingBuffer     *link;
++
++  /*< private >*/
++  gpointer _gst_reserved[GST_PADDING];
++};
++
++/**
++ * GstAudioRingBufferClass:
++ * @parent_class: the parent class structure.
++ * @process: Write/Read data to/from the device.
++ * @reset: Returns as quickly as possible from a write/read and flush any pending
++ *         samples from the device.
++ *
++ * #GstAudioRingBuffer class. Override the vmethods to implement functionality.
++ */
++struct _GstAudioRingBufferClass {
++  GstRingBufferClass parent_class;
++
++  /* vtable */
++
++  /* write/read samples to the device */
++  gint      (*process)   (GstAudioRingBuffer *buf, gpointer data, guint length);
++  /* reset the audio device, unblock from a read/write */
++  void      (*reset)     (GstAudioRingBuffer *buf);
++
++  /*< private >*/
++  gpointer _gst_reserved[GST_PADDING];
++};
++
++GType gst_audio_ring_buffer_get_type(void);
++
++gboolean gst_audio_ring_buffer_link       (GstAudioRingBuffer *buf1, GstAudioRingBuffer *buf2);
++
++gboolean gst_audio_ring_buffer_set_thread (GstAudioRingBuffer *buf, GstRingBufferThread *thread);
++
++G_END_DECLS
++
++#endif /* __GST_AUDIO_RING_BUFFER_H__ */
index 0000000,0000000..1c2c72c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1129 @@@
++/* GStreamer
++ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
++ *                    2005 Wim Taymans <wim@fluendo.com>
++ *
++ * gstbaseaudiosrc.c: 
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/**
++ * SECTION:gstbaseaudiosrc
++ * @short_description: Base class for audio sources
++ * @see_also: #GstAudioSrc, #GstRingBuffer.
++ *
++ * This is the base class for audio sources. Subclasses need to implement the
++ * ::create_ringbuffer vmethod. This base class will then take care of
++ * reading samples from the ringbuffer, synchronisation and flushing.
++ *
++ * Last reviewed on 2006-09-27 (0.10.12)
++ */
++
++#ifdef HAVE_CONFIG_H
++#  include "config.h"
++#endif
++
++#include <string.h>
++
++#include "gstbaseaudiosrc.h"
++
++#include "gst/gst-i18n-plugin.h"
++
++GST_DEBUG_CATEGORY_STATIC (gst_base_audio_src_debug);
++#define GST_CAT_DEFAULT gst_base_audio_src_debug
++
++GType
++gst_base_audio_src_slave_method_get_type (void)
++{
++  static GType slave_method_type = 0;
++  static const GEnumValue slave_method[] = {
++    {GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE, "Resampling slaving", "resample"},
++    {GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP, "Re-timestamp", "re-timestamp"},
++    {GST_BASE_AUDIO_SRC_SLAVE_SKEW, "Skew", "skew"},
++    {GST_BASE_AUDIO_SRC_SLAVE_NONE, "No slaving", "none"},
++    {0, NULL, NULL},
++  };
++
++  if (!slave_method_type) {
++    slave_method_type =
++        g_enum_register_static ("GstBaseAudioSrcSlaveMethod", slave_method);
++  }
++  return slave_method_type;
++}
++
++#define GST_BASE_AUDIO_SRC_GET_PRIVATE(obj)  \
++   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_SRC, GstBaseAudioSrcPrivate))
++
++struct _GstBaseAudioSrcPrivate
++{
++  gboolean provide_clock;
++
++  /* the clock slaving algorithm in use */
++  GstBaseAudioSrcSlaveMethod slave_method;
++};
++
++/* BaseAudioSrc signals and args */
++enum
++{
++  /* FILL ME */
++  LAST_SIGNAL
++};
++
++#define DEFAULT_BUFFER_TIME     ((200 * GST_MSECOND) / GST_USECOND)
++#define DEFAULT_LATENCY_TIME    ((10 * GST_MSECOND) / GST_USECOND)
++#define DEFAULT_ACTUAL_BUFFER_TIME     -1
++#define DEFAULT_ACTUAL_LATENCY_TIME    -1
++#define DEFAULT_PROVIDE_CLOCK   TRUE
++#define DEFAULT_SLAVE_METHOD    GST_BASE_AUDIO_SRC_SLAVE_SKEW
++
++enum
++{
++  PROP_0,
++  PROP_BUFFER_TIME,
++  PROP_LATENCY_TIME,
++  PROP_ACTUAL_BUFFER_TIME,
++  PROP_ACTUAL_LATENCY_TIME,
++  PROP_PROVIDE_CLOCK,
++  PROP_SLAVE_METHOD,
++  PROP_LAST
++};
++
++static void
++_do_init (GType type)
++{
++  GST_DEBUG_CATEGORY_INIT (gst_base_audio_src_debug, "baseaudiosrc", 0,
++      "baseaudiosrc element");
++
++#ifdef ENABLE_NLS
++  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
++      LOCALEDIR);
++  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
++  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
++#endif /* ENABLE_NLS */
++}
++
++GST_BOILERPLATE_FULL (GstBaseAudioSrc, gst_base_audio_src, GstPushSrc,
++    GST_TYPE_PUSH_SRC, _do_init);
++
++static void gst_base_audio_src_set_property (GObject * object, guint prop_id,
++    const GValue * value, GParamSpec * pspec);
++static void gst_base_audio_src_get_property (GObject * object, guint prop_id,
++    GValue * value, GParamSpec * pspec);
++static void gst_base_audio_src_dispose (GObject * object);
++
++static GstStateChangeReturn gst_base_audio_src_change_state (GstElement *
++    element, GstStateChange transition);
++
++static GstClock *gst_base_audio_src_provide_clock (GstElement * elem);
++static GstClockTime gst_base_audio_src_get_time (GstClock * clock,
++    GstBaseAudioSrc * src);
++
++static GstFlowReturn gst_base_audio_src_create (GstBaseSrc * bsrc,
++    guint64 offset, guint length, GstBuffer ** buf);
++static gboolean gst_base_audio_src_check_get_range (GstBaseSrc * bsrc);
++
++static gboolean gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event);
++static void gst_base_audio_src_get_times (GstBaseSrc * bsrc,
++    GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
++static gboolean gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
++static gboolean gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query);
++static void gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
++
++/* static guint gst_base_audio_src_signals[LAST_SIGNAL] = { 0 }; */
++
++static void
++gst_base_audio_src_base_init (gpointer g_class)
++{
++}
++
++static void
++gst_base_audio_src_class_init (GstBaseAudioSrcClass * klass)
++{
++  GObjectClass *gobject_class;
++  GstElementClass *gstelement_class;
++  GstBaseSrcClass *gstbasesrc_class;
++
++  gobject_class = (GObjectClass *) klass;
++  gstelement_class = (GstElementClass *) klass;
++  gstbasesrc_class = (GstBaseSrcClass *) klass;
++
++  g_type_class_add_private (klass, sizeof (GstBaseAudioSrcPrivate));
++
++  gobject_class->set_property =
++      GST_DEBUG_FUNCPTR (gst_base_audio_src_set_property);
++  gobject_class->get_property =
++      GST_DEBUG_FUNCPTR (gst_base_audio_src_get_property);
++  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_src_dispose);
++
++  g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
++      g_param_spec_int64 ("buffer-time", "Buffer Time",
++          "Size of audio buffer in microseconds", 1,
++          G_MAXINT64, DEFAULT_BUFFER_TIME,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++
++  g_object_class_install_property (gobject_class, PROP_LATENCY_TIME,
++      g_param_spec_int64 ("latency-time", "Latency Time",
++          "Audio latency in microseconds", 1,
++          G_MAXINT64, DEFAULT_LATENCY_TIME,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++
++  /**
++   * GstBaseAudioSrc:actual-buffer-time:
++   *
++   * Actual configured size of audio buffer in microseconds.
++   *
++   * Since: 0.10.20
++   **/
++  g_object_class_install_property (gobject_class, PROP_ACTUAL_BUFFER_TIME,
++      g_param_spec_int64 ("actual-buffer-time", "Actual Buffer Time",
++          "Actual configured size of audio buffer in microseconds",
++          DEFAULT_ACTUAL_BUFFER_TIME, G_MAXINT64, DEFAULT_ACTUAL_BUFFER_TIME,
++          G_PARAM_READABLE));
++
++  /**
++   * GstBaseAudioSrc:actual-latency-time:
++   *
++   * Actual configured audio latency in microseconds.
++   *
++   * Since: 0.10.20
++   **/
++  g_object_class_install_property (gobject_class, PROP_ACTUAL_LATENCY_TIME,
++      g_param_spec_int64 ("actual-latency-time", "Actual Latency Time",
++          "Actual configured audio latency in microseconds",
++          DEFAULT_ACTUAL_LATENCY_TIME, G_MAXINT64, DEFAULT_ACTUAL_LATENCY_TIME,
++          G_PARAM_READABLE));
++
++  g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK,
++      g_param_spec_boolean ("provide-clock", "Provide Clock",
++          "Provide a clock to be used as the global pipeline clock",
++          DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++
++  g_object_class_install_property (gobject_class, PROP_SLAVE_METHOD,
++      g_param_spec_enum ("slave-method", "Slave Method",
++          "Algorithm to use to match the rate of the masterclock",
++          GST_TYPE_BASE_AUDIO_SRC_SLAVE_METHOD, DEFAULT_SLAVE_METHOD,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++
++  gstelement_class->change_state =
++      GST_DEBUG_FUNCPTR (gst_base_audio_src_change_state);
++  gstelement_class->provide_clock =
++      GST_DEBUG_FUNCPTR (gst_base_audio_src_provide_clock);
++
++  gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_src_setcaps);
++  gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_src_event);
++  gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_base_audio_src_query);
++  gstbasesrc_class->get_times =
++      GST_DEBUG_FUNCPTR (gst_base_audio_src_get_times);
++  gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_base_audio_src_create);
++  gstbasesrc_class->check_get_range =
++      GST_DEBUG_FUNCPTR (gst_base_audio_src_check_get_range);
++  gstbasesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_base_audio_src_fixate);
++
++  /* ref class from a thread-safe context to work around missing bit of
++   * thread-safety in GObject */
++  g_type_class_ref (GST_TYPE_AUDIO_CLOCK);
++  g_type_class_ref (GST_TYPE_RING_BUFFER);
++}
++
++static void
++gst_base_audio_src_init (GstBaseAudioSrc * baseaudiosrc,
++    GstBaseAudioSrcClass * g_class)
++{
++  baseaudiosrc->priv = GST_BASE_AUDIO_SRC_GET_PRIVATE (baseaudiosrc);
++
++  baseaudiosrc->buffer_time = DEFAULT_BUFFER_TIME;
++  baseaudiosrc->latency_time = DEFAULT_LATENCY_TIME;
++  baseaudiosrc->priv->provide_clock = DEFAULT_PROVIDE_CLOCK;
++  baseaudiosrc->priv->slave_method = DEFAULT_SLAVE_METHOD;
++  /* reset blocksize we use latency time to calculate a more useful 
++   * value based on negotiated format. */
++  GST_BASE_SRC (baseaudiosrc)->blocksize = 0;
++
++  baseaudiosrc->clock = gst_audio_clock_new ("GstAudioSrcClock",
++      (GstAudioClockGetTimeFunc) gst_base_audio_src_get_time, baseaudiosrc);
++
++  /* we are always a live source */
++  gst_base_src_set_live (GST_BASE_SRC (baseaudiosrc), TRUE);
++  /* we operate in time */
++  gst_base_src_set_format (GST_BASE_SRC (baseaudiosrc), GST_FORMAT_TIME);
++}
++
++static void
++gst_base_audio_src_dispose (GObject * object)
++{
++  GstBaseAudioSrc *src;
++
++  src = GST_BASE_AUDIO_SRC (object);
++
++  GST_OBJECT_LOCK (src);
++  if (src->clock)
++    gst_object_unref (src->clock);
++  src->clock = NULL;
++
++  if (src->ringbuffer) {
++    gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer));
++    src->ringbuffer = NULL;
++  }
++  GST_OBJECT_UNLOCK (src);
++
++  G_OBJECT_CLASS (parent_class)->dispose (object);
++}
++
++static GstClock *
++gst_base_audio_src_provide_clock (GstElement * elem)
++{
++  GstBaseAudioSrc *src;
++  GstClock *clock;
++
++  src = GST_BASE_AUDIO_SRC (elem);
++
++  /* we have no ringbuffer (must be NULL state) */
++  if (src->ringbuffer == NULL)
++    goto wrong_state;
++
++  if (!gst_ring_buffer_is_acquired (src->ringbuffer))
++    goto wrong_state;
++
++  GST_OBJECT_LOCK (src);
++  if (!src->priv->provide_clock)
++    goto clock_disabled;
++
++  clock = GST_CLOCK_CAST (gst_object_ref (src->clock));
++  GST_OBJECT_UNLOCK (src);
++
++  return clock;
++
++  /* ERRORS */
++wrong_state:
++  {
++    GST_DEBUG_OBJECT (src, "ringbuffer not acquired");
++    return NULL;
++  }
++clock_disabled:
++  {
++    GST_DEBUG_OBJECT (src, "clock provide disabled");
++    GST_OBJECT_UNLOCK (src);
++    return NULL;
++  }
++}
++
++static GstClockTime
++gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src)
++{
++  guint64 raw, samples;
++  guint delay;
++  GstClockTime result;
++
++  if (G_UNLIKELY (src->ringbuffer == NULL || src->ringbuffer->spec.rate == 0))
++    return GST_CLOCK_TIME_NONE;
++
++  raw = samples = gst_ring_buffer_samples_done (src->ringbuffer);
++
++  /* the number of samples not yet processed, this is still queued in the
++   * device (not yet read for capture). */
++  delay = gst_ring_buffer_delay (src->ringbuffer);
++
++  samples += delay;
++
++  result = gst_util_uint64_scale_int (samples, GST_SECOND,
++      src->ringbuffer->spec.rate);
++
++  GST_DEBUG_OBJECT (src,
++      "processed samples: raw %llu, delay %u, real %llu, time %"
++      GST_TIME_FORMAT, raw, delay, samples, GST_TIME_ARGS (result));
++
++  return result;
++}
++
++static gboolean
++gst_base_audio_src_check_get_range (GstBaseSrc * bsrc)
++{
++  /* we allow limited pull base operation of which the details
++   * will eventually exposed in an as of yet non-existing query.
++   * Basically pulling can be done on any number of bytes as long
++   * as the offset is -1 or sequentially increasing. */
++  return TRUE;
++}
++
++/**
++ * gst_base_audio_src_set_provide_clock:
++ * @src: a #GstBaseAudioSrc
++ * @provide: new state
++ *
++ * Controls whether @src will provide a clock or not. If @provide is %TRUE, 
++ * gst_element_provide_clock() will return a clock that reflects the datarate
++ * of @src. If @provide is %FALSE, gst_element_provide_clock() will return NULL.
++ *
++ * Since: 0.10.16
++ */
++void
++gst_base_audio_src_set_provide_clock (GstBaseAudioSrc * src, gboolean provide)
++{
++  g_return_if_fail (GST_IS_BASE_AUDIO_SRC (src));
++
++  GST_OBJECT_LOCK (src);
++  src->priv->provide_clock = provide;
++  GST_OBJECT_UNLOCK (src);
++}
++
++/**
++ * gst_base_audio_src_get_provide_clock:
++ * @src: a #GstBaseAudioSrc
++ *
++ * Queries whether @src will provide a clock or not. See also
++ * gst_base_audio_src_set_provide_clock.
++ *
++ * Returns: %TRUE if @src will provide a clock.
++ *
++ * Since: 0.10.16
++ */
++gboolean
++gst_base_audio_src_get_provide_clock (GstBaseAudioSrc * src)
++{
++  gboolean result;
++
++  g_return_val_if_fail (GST_IS_BASE_AUDIO_SRC (src), FALSE);
++
++  GST_OBJECT_LOCK (src);
++  result = src->priv->provide_clock;
++  GST_OBJECT_UNLOCK (src);
++
++  return result;
++}
++
++/**
++ * gst_base_audio_src_set_slave_method:
++ * @src: a #GstBaseAudioSrc
++ * @method: the new slave method
++ *
++ * Controls how clock slaving will be performed in @src. 
++ *
++ * Since: 0.10.20
++ */
++void
++gst_base_audio_src_set_slave_method (GstBaseAudioSrc * src,
++    GstBaseAudioSrcSlaveMethod method)
++{
++  g_return_if_fail (GST_IS_BASE_AUDIO_SRC (src));
++
++  GST_OBJECT_LOCK (src);
++  src->priv->slave_method = method;
++  GST_OBJECT_UNLOCK (src);
++}
++
++/**
++ * gst_base_audio_src_get_slave_method:
++ * @src: a #GstBaseAudioSrc
++ *
++ * Get the current slave method used by @src.
++ *
++ * Returns: The current slave method used by @src.
++ *
++ * Since: 0.10.20
++ */
++GstBaseAudioSrcSlaveMethod
++gst_base_audio_src_get_slave_method (GstBaseAudioSrc * src)
++{
++  GstBaseAudioSrcSlaveMethod result;
++
++  g_return_val_if_fail (GST_IS_BASE_AUDIO_SRC (src), -1);
++
++  GST_OBJECT_LOCK (src);
++  result = src->priv->slave_method;
++  GST_OBJECT_UNLOCK (src);
++
++  return result;
++}
++
++static void
++gst_base_audio_src_set_property (GObject * object, guint prop_id,
++    const GValue * value, GParamSpec * pspec)
++{
++  GstBaseAudioSrc *src;
++
++  src = GST_BASE_AUDIO_SRC (object);
++
++  switch (prop_id) {
++    case PROP_BUFFER_TIME:
++      src->buffer_time = g_value_get_int64 (value);
++      break;
++    case PROP_LATENCY_TIME:
++      src->latency_time = g_value_get_int64 (value);
++      break;
++    case PROP_PROVIDE_CLOCK:
++      gst_base_audio_src_set_provide_clock (src, g_value_get_boolean (value));
++      break;
++    case PROP_SLAVE_METHOD:
++      gst_base_audio_src_set_slave_method (src, g_value_get_enum (value));
++      break;
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++  }
++}
++
++static void
++gst_base_audio_src_get_property (GObject * object, guint prop_id,
++    GValue * value, GParamSpec * pspec)
++{
++  GstBaseAudioSrc *src;
++
++  src = GST_BASE_AUDIO_SRC (object);
++
++  switch (prop_id) {
++    case PROP_BUFFER_TIME:
++      g_value_set_int64 (value, src->buffer_time);
++      break;
++    case PROP_LATENCY_TIME:
++      g_value_set_int64 (value, src->latency_time);
++      break;
++    case PROP_ACTUAL_BUFFER_TIME:
++      GST_OBJECT_LOCK (src);
++      if (src->ringbuffer && src->ringbuffer->acquired)
++        g_value_set_int64 (value, src->ringbuffer->spec.buffer_time);
++      else
++        g_value_set_int64 (value, DEFAULT_ACTUAL_BUFFER_TIME);
++      GST_OBJECT_UNLOCK (src);
++      break;
++    case PROP_ACTUAL_LATENCY_TIME:
++      GST_OBJECT_LOCK (src);
++      if (src->ringbuffer && src->ringbuffer->acquired)
++        g_value_set_int64 (value, src->ringbuffer->spec.latency_time);
++      else
++        g_value_set_int64 (value, DEFAULT_ACTUAL_LATENCY_TIME);
++      GST_OBJECT_UNLOCK (src);
++      break;
++    case PROP_PROVIDE_CLOCK:
++      g_value_set_boolean (value, gst_base_audio_src_get_provide_clock (src));
++      break;
++    case PROP_SLAVE_METHOD:
++      g_value_set_enum (value, gst_base_audio_src_get_slave_method (src));
++      break;
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++  }
++}
++
++static void
++gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
++{
++  GstStructure *s;
++  gint width, depth;
++
++  s = gst_caps_get_structure (caps, 0);
++
++  /* fields for all formats */
++  gst_structure_fixate_field_nearest_int (s, "rate", 44100);
++  gst_structure_fixate_field_nearest_int (s, "channels", 2);
++  gst_structure_fixate_field_nearest_int (s, "width", 16);
++
++  /* fields for int */
++  if (gst_structure_has_field (s, "depth")) {
++    gst_structure_get_int (s, "width", &width);
++    /* round width to nearest multiple of 8 for the depth */
++    depth = GST_ROUND_UP_8 (width);
++    gst_structure_fixate_field_nearest_int (s, "depth", depth);
++  }
++  if (gst_structure_has_field (s, "signed"))
++    gst_structure_fixate_field_boolean (s, "signed", TRUE);
++  if (gst_structure_has_field (s, "endianness"))
++    gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER);
++}
++
++static gboolean
++gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
++{
++  GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
++  GstRingBufferSpec *spec;
++
++  spec = &src->ringbuffer->spec;
++
++  spec->buffer_time = src->buffer_time;
++  spec->latency_time = src->latency_time;
++
++  if (!gst_ring_buffer_parse_caps (spec, caps))
++    goto parse_error;
++
++  /* calculate suggested segsize and segtotal */
++  spec->segsize =
++      spec->rate * spec->bytes_per_sample * spec->latency_time / GST_MSECOND;
++  spec->segtotal = spec->buffer_time / spec->latency_time;
++
++  GST_DEBUG ("release old ringbuffer");
++
++  gst_ring_buffer_release (src->ringbuffer);
++
++  gst_ring_buffer_debug_spec_buff (spec);
++
++  GST_DEBUG ("acquire new ringbuffer");
++
++  if (!gst_ring_buffer_acquire (src->ringbuffer, spec))
++    goto acquire_error;
++
++  /* calculate actual latency and buffer times */
++  spec->latency_time =
++      spec->segsize * GST_MSECOND / (spec->rate * spec->bytes_per_sample);
++  spec->buffer_time =
++      spec->segtotal * spec->segsize * GST_MSECOND / (spec->rate *
++      spec->bytes_per_sample);
++
++  gst_ring_buffer_debug_spec_buff (spec);
++
++  g_object_notify (G_OBJECT (src), "actual-buffer-time");
++  g_object_notify (G_OBJECT (src), "actual-latency-time");
++
++  return TRUE;
++
++  /* ERRORS */
++parse_error:
++  {
++    GST_DEBUG ("could not parse caps");
++    return FALSE;
++  }
++acquire_error:
++  {
++    GST_DEBUG ("could not acquire ringbuffer");
++    return FALSE;
++  }
++}
++
++static void
++gst_base_audio_src_get_times (GstBaseSrc * bsrc, GstBuffer * buffer,
++    GstClockTime * start, GstClockTime * end)
++{
++  /* no need to sync to a clock here, we schedule the samples based
++   * on our own clock for the moment. */
++  *start = GST_CLOCK_TIME_NONE;
++  *end = GST_CLOCK_TIME_NONE;
++}
++
++static gboolean
++gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query)
++{
++  GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
++  gboolean res = FALSE;
++
++  switch (GST_QUERY_TYPE (query)) {
++    case GST_QUERY_LATENCY:
++    {
++      GstClockTime min_latency, max_latency;
++      GstRingBufferSpec *spec;
++
++      if (G_UNLIKELY (src->ringbuffer == NULL
++              || src->ringbuffer->spec.rate == 0))
++        goto done;
++
++      spec = &src->ringbuffer->spec;
++
++      /* we have at least 1 segment of latency */
++      min_latency =
++          gst_util_uint64_scale_int (spec->segsize, GST_SECOND,
++          spec->rate * spec->bytes_per_sample);
++      /* we cannot delay more than the buffersize else we lose data */
++      max_latency =
++          gst_util_uint64_scale_int (spec->segtotal * spec->segsize, GST_SECOND,
++          spec->rate * spec->bytes_per_sample);
++
++      GST_DEBUG_OBJECT (src,
++          "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
++          GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
++
++      /* we are always live, the min latency is 1 segment and the max latency is
++       * the complete buffer of segments. */
++      gst_query_set_latency (query, TRUE, min_latency, max_latency);
++
++      res = TRUE;
++      break;
++    }
++    default:
++      res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
++      break;
++  }
++done:
++  return res;
++}
++
++static gboolean
++gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event)
++{
++  GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
++  gboolean res;
++
++  res = TRUE;
++
++  switch (GST_EVENT_TYPE (event)) {
++    case GST_EVENT_FLUSH_START:
++      GST_DEBUG_OBJECT (bsrc, "flush-start");
++      gst_ring_buffer_pause (src->ringbuffer);
++      gst_ring_buffer_clear_all (src->ringbuffer);
++      break;
++    case GST_EVENT_FLUSH_STOP:
++      GST_DEBUG_OBJECT (bsrc, "flush-stop");
++      /* always resync on sample after a flush */
++      src->next_sample = -1;
++      gst_ring_buffer_clear_all (src->ringbuffer);
++      break;
++    case GST_EVENT_SEEK:
++      GST_DEBUG_OBJECT (bsrc, "refuse to seek");
++      res = FALSE;
++      break;
++    default:
++      GST_DEBUG_OBJECT (bsrc, "dropping event %p", event);
++      break;
++  }
++  return res;
++}
++
++/* get the next offset in the ringbuffer for reading samples.
++ * If the next sample is too far away, this function will position itself to the
++ * next most recent sample, creating discontinuity */
++static guint64
++gst_base_audio_src_get_offset (GstBaseAudioSrc * src)
++{
++  guint64 sample;
++  gint readseg, segdone, segtotal, sps;
++  gint diff;
++
++  /* assume we can append to the previous sample */
++  sample = src->next_sample;
++  /* no previous sample, try to read from position 0 */
++  if (sample == -1)
++    sample = 0;
++
++  sps = src->ringbuffer->samples_per_seg;
++  segtotal = src->ringbuffer->spec.segtotal;
++
++  /* figure out the segment and the offset inside the segment where
++   * the sample should be read from. */
++  readseg = sample / sps;
++
++  /* get the currently processed segment */
++  segdone = g_atomic_int_get (&src->ringbuffer->segdone)
++      - src->ringbuffer->segbase;
++
++  GST_DEBUG_OBJECT (src, "reading from %d, we are at %d", readseg, segdone);
++
++  /* see how far away it is from the read segment, normally segdone (where new
++   * data is written in the ringbuffer) is bigger than readseg (where we are
++   * reading). */
++  diff = segdone - readseg;
++  if (diff >= segtotal) {
++    GST_DEBUG_OBJECT (src, "dropped, align to segment %d", segdone);
++    /* sample would be dropped, position to next playable position */
++    sample = ((guint64) (segdone)) * sps;
++  }
++
++  return sample;
++}
++
++static GstFlowReturn
++gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
++    GstBuffer ** outbuf)
++{
++  GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
++  GstBuffer *buf;
++  guchar *data;
++  guint samples, total_samples;
++  guint64 sample;
++  gint bps;
++  GstRingBuffer *ringbuffer;
++  GstRingBufferSpec *spec;
++  guint read;
++  GstClockTime timestamp, duration;
++  GstClock *clock;
++
++  ringbuffer = src->ringbuffer;
++  spec = &ringbuffer->spec;
++
++  if (G_UNLIKELY (!gst_ring_buffer_is_acquired (ringbuffer)))
++    goto wrong_state;
++
++  bps = spec->bytes_per_sample;
++
++  if ((length == 0 && bsrc->blocksize == 0) || length == -1)
++    /* no length given, use the default segment size */
++    length = spec->segsize;
++  else
++    /* make sure we round down to an integral number of samples */
++    length -= length % bps;
++
++  /* figure out the offset in the ringbuffer */
++  if (G_UNLIKELY (offset != -1)) {
++    sample = offset / bps;
++    /* if a specific offset was given it must be the next sequential
++     * offset we expect or we fail for now. */
++    if (src->next_sample != -1 && sample != src->next_sample)
++      goto wrong_offset;
++  } else {
++    /* calculate the sequentially next sample we need to read. This can jump and
++     * create a DISCONT. */
++    sample = gst_base_audio_src_get_offset (src);
++  }
++
++  GST_DEBUG_OBJECT (src, "reading from sample %" G_GUINT64_FORMAT, sample);
++
++  /* get the number of samples to read */
++  total_samples = samples = length / bps;
++
++  /* FIXME, using a bufferpool would be nice here */
++  buf = gst_buffer_new_and_alloc (length);
++  data = GST_BUFFER_DATA (buf);
++
++  do {
++    read = gst_ring_buffer_read (ringbuffer, sample, data, samples);
++    GST_DEBUG_OBJECT (src, "read %u of %u", read, samples);
++    /* if we read all, we're done */
++    if (read == samples)
++      break;
++
++    /* else something interrupted us and we wait for playing again. */
++    GST_DEBUG_OBJECT (src, "wait playing");
++    if (gst_base_src_wait_playing (bsrc) != GST_FLOW_OK)
++      goto stopped;
++
++    GST_DEBUG_OBJECT (src, "continue playing");
++
++    /* read next samples */
++    sample += read;
++    samples -= read;
++    data += read * bps;
++  } while (TRUE);
++
++  /* mark discontinuity if needed */
++  if (G_UNLIKELY (sample != src->next_sample) && src->next_sample != -1) {
++    GST_WARNING_OBJECT (src,
++        "create DISCONT of %" G_GUINT64_FORMAT " samples at sample %"
++        G_GUINT64_FORMAT, sample - src->next_sample, sample);
++    GST_ELEMENT_WARNING (src, CORE, CLOCK,
++        (_("Can't record audio fast enough")),
++        ("Dropped %" G_GUINT64_FORMAT " samples. This is most likely because "
++            "downstream can't keep up and is consuming samples too slowly.",
++            sample - src->next_sample));
++    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
++  }
++
++  src->next_sample = sample + samples;
++
++  /* get the normal timestamp to get the duration. */
++  timestamp = gst_util_uint64_scale_int (sample, GST_SECOND, spec->rate);
++  duration = gst_util_uint64_scale_int (src->next_sample, GST_SECOND,
++      spec->rate) - timestamp;
++
++  GST_OBJECT_LOCK (src);
++  if (!(clock = GST_ELEMENT_CLOCK (src)))
++    goto no_sync;
++
++  if (clock != src->clock) {
++    /* we are slaved, check how to handle this */
++    switch (src->priv->slave_method) {
++      case GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE:
++        /* not implemented, use skew algorithm. This algorithm should
++         * work on the readout pointer and produces more or less samples based
++         * on the clock drift */
++      case GST_BASE_AUDIO_SRC_SLAVE_SKEW:
++      {
++        GstClockTime running_time;
++        GstClockTime base_time;
++        GstClockTime current_time;
++        guint64 running_time_sample;
++        gint running_time_segment;
++        gint current_segment;
++        gint segment_skew;
++        gint sps;
++
++        /* samples per segment */
++        sps = ringbuffer->samples_per_seg;
++
++        /* get the current time */
++        current_time = gst_clock_get_time (clock);
++
++        /* get the basetime */
++        base_time = GST_ELEMENT_CAST (src)->base_time;
++
++        /* get the running_time */
++        running_time = current_time - base_time;
++
++        /* the running_time converted to a sample (relative to the ringbuffer) */
++        running_time_sample =
++            gst_util_uint64_scale_int (running_time, spec->rate, GST_SECOND);
++
++        /* the segmentnr corrensponding to running_time, round down */
++        running_time_segment = running_time_sample / sps;
++
++        /* the segment currently read from the ringbuffer */
++        current_segment = sample / sps;
++
++        /* the skew we have between running_time and the ringbuffertime */
++        segment_skew = running_time_segment - current_segment;
++
++        GST_DEBUG_OBJECT (bsrc, "\n running_time = %" GST_TIME_FORMAT
++            "\n timestamp     = %" GST_TIME_FORMAT
++            "\n running_time_segment = %d"
++            "\n current_segment      = %d"
++            "\n segment_skew         = %d",
++            GST_TIME_ARGS (running_time),
++            GST_TIME_ARGS (timestamp),
++            running_time_segment, current_segment, segment_skew);
++
++        /* Resync the ringbuffer if:
++         * 1. We get one segment into the future.
++         *    This is clearly a lie, because we can't
++         *    possibly have a buffer with timestamp 1 at
++         *    time 0. (unless it has time-travelled...)
++         *
++         * 2. We are more than the length of the ringbuffer behind.
++         *    The length of the ringbuffer then gets to dictate
++         *    the threshold for what is concidered "too late"
++         *
++         * 3. If this is our first buffer.
++         *    We know that we should catch up to running_time
++         *    the first time we are ran.
++         */
++        if ((segment_skew < 0) ||
++            (segment_skew >= ringbuffer->spec.segtotal) ||
++            (current_segment == 0)) {
++          gint segments_written;
++          gint first_segment;
++          gint last_segment;
++          gint new_last_segment;
++          gint segment_diff;
++          gint new_first_segment;
++          guint64 new_sample;
++
++          /* we are going to say that the last segment was captured at the current time
++             (running_time), minus one segment of creation-latency in the ringbuffer.
++             This can be thought of as: The segment arrived in the ringbuffer at time X, and
++             that means it was created at time X - (one segment). */
++          new_last_segment = running_time_segment - 1;
++
++          /* for better readablity */
++          first_segment = current_segment;
++
++          /* get the amount of segments written from the device by now */
++          segments_written = g_atomic_int_get (&ringbuffer->segdone);
++
++          /* subtract the base to segments_written to get the number of the
++             last written segment in the ringbuffer (one segment written = segment 0) */
++          last_segment = segments_written - ringbuffer->segbase - 1;
++
++          /* we see how many segments the ringbuffer was timeshifted */
++          segment_diff = new_last_segment - last_segment;
++
++          /* we move the first segment an equal amount */
++          new_first_segment = first_segment + segment_diff;
++
++          /* and we also move the segmentbase the same amount */
++          ringbuffer->segbase -= segment_diff;
++
++          /* we calculate the new sample value */
++          new_sample = ((guint64) new_first_segment) * sps;
++
++          /* and get the relative time to this -> our new timestamp */
++          timestamp =
++              gst_util_uint64_scale_int (new_sample, GST_SECOND, spec->rate);
++
++          /* we update the next sample accordingly */
++          src->next_sample = new_sample + samples;
++
++          GST_DEBUG_OBJECT (bsrc,
++              "Timeshifted the ringbuffer with %d segments: "
++              "Updating the timestamp to %" GST_TIME_FORMAT ", "
++              "and src->next_sample to %" G_GUINT64_FORMAT, segment_diff,
++              GST_TIME_ARGS (timestamp), src->next_sample);
++        }
++        break;
++      }
++      case GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP:
++      {
++        GstClockTime base_time, latency;
++
++        /* We are slaved to another clock, take running time of the pipeline clock and
++         * timestamp against it. Somebody else in the pipeline should figure out the
++         * clock drift. We keep the duration we calculated above. */
++        timestamp = gst_clock_get_time (clock);
++        base_time = GST_ELEMENT_CAST (src)->base_time;
++
++        if (timestamp > base_time)
++          timestamp -= base_time;
++        else
++          timestamp = 0;
++
++        /* subtract latency */
++        latency =
++            gst_util_uint64_scale_int (total_samples, GST_SECOND, spec->rate);
++        if (timestamp > latency)
++          timestamp -= latency;
++        else
++          timestamp = 0;
++      }
++      case GST_BASE_AUDIO_SRC_SLAVE_NONE:
++        break;
++    }
++  } else {
++    GstClockTime base_time;
++
++    /* to get the timestamp against the clock we also need to add our offset */
++    timestamp = gst_audio_clock_adjust (clock, timestamp);
++
++    /* we are not slaved, subtract base_time */
++    base_time = GST_ELEMENT_CAST (src)->base_time;
++
++    if (timestamp > base_time) {
++      timestamp -= base_time;
++      GST_LOG_OBJECT (src,
++          "buffer timestamp %" GST_TIME_FORMAT " (base_time %" GST_TIME_FORMAT
++          ")", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (base_time));
++    } else {
++      GST_LOG_OBJECT (src,
++          "buffer timestamp 0, ts %" GST_TIME_FORMAT " <= base_time %"
++          GST_TIME_FORMAT, GST_TIME_ARGS (timestamp),
++          GST_TIME_ARGS (base_time));
++      timestamp = 0;
++    }
++  }
++
++no_sync:
++  GST_OBJECT_UNLOCK (src);
++
++  GST_BUFFER_TIMESTAMP (buf) = timestamp;
++  GST_BUFFER_DURATION (buf) = duration;
++  GST_BUFFER_OFFSET (buf) = sample;
++  GST_BUFFER_OFFSET_END (buf) = sample + samples;
++
++  *outbuf = buf;
++
++  return GST_FLOW_OK;
++
++  /* ERRORS */
++wrong_state:
++  {
++    GST_DEBUG_OBJECT (src, "ringbuffer in wrong state");
++    return GST_FLOW_WRONG_STATE;
++  }
++wrong_offset:
++  {
++    GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
++        (NULL), ("resource can only be operated on sequentially but offset %"
++            G_GUINT64_FORMAT " was given", offset));
++    return GST_FLOW_ERROR;
++  }
++stopped:
++  {
++    gst_buffer_unref (buf);
++    GST_DEBUG_OBJECT (src, "ringbuffer stopped");
++    return GST_FLOW_WRONG_STATE;
++  }
++}
++
++/**
++ * gst_base_audio_src_create_ringbuffer:
++ * @src: a #GstBaseAudioSrc.
++ *
++ * Create and return the #GstRingBuffer for @src. This function will call the
++ * ::create_ringbuffer vmethod and will set @src as the parent of the returned
++ * buffer (see gst_object_set_parent()).
++ *
++ * Returns: The new ringbuffer of @src.
++ */
++GstRingBuffer *
++gst_base_audio_src_create_ringbuffer (GstBaseAudioSrc * src)
++{
++  GstBaseAudioSrcClass *bclass;
++  GstRingBuffer *buffer = NULL;
++
++  bclass = GST_BASE_AUDIO_SRC_GET_CLASS (src);
++  if (bclass->create_ringbuffer)
++    buffer = bclass->create_ringbuffer (src);
++
++  if (G_LIKELY (buffer))
++    gst_object_set_parent (GST_OBJECT_CAST (buffer), GST_OBJECT_CAST (src));
++
++  return buffer;
++}
++
++static GstStateChangeReturn
++gst_base_audio_src_change_state (GstElement * element,
++    GstStateChange transition)
++{
++  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
++  GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (element);
++
++  switch (transition) {
++    case GST_STATE_CHANGE_NULL_TO_READY:
++      GST_DEBUG_OBJECT (src, "NULL->READY");
++      GST_OBJECT_LOCK (src);
++      if (src->ringbuffer == NULL) {
++        gst_audio_clock_reset (GST_AUDIO_CLOCK (src->clock), 0);
++        src->ringbuffer = gst_base_audio_src_create_ringbuffer (src);
++      }
++      GST_OBJECT_UNLOCK (src);
++      if (!gst_ring_buffer_open_device (src->ringbuffer))
++        goto open_failed;
++      break;
++    case GST_STATE_CHANGE_READY_TO_PAUSED:
++      GST_DEBUG_OBJECT (src, "READY->PAUSED");
++      src->next_sample = -1;
++      gst_ring_buffer_set_flushing (src->ringbuffer, FALSE);
++      gst_ring_buffer_may_start (src->ringbuffer, FALSE);
++      break;
++    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
++      GST_DEBUG_OBJECT (src, "PAUSED->PLAYING");
++      gst_ring_buffer_may_start (src->ringbuffer, TRUE);
++      break;
++    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
++      GST_DEBUG_OBJECT (src, "PLAYING->PAUSED");
++      gst_ring_buffer_may_start (src->ringbuffer, FALSE);
++      gst_ring_buffer_pause (src->ringbuffer);
++      break;
++    case GST_STATE_CHANGE_PAUSED_TO_READY:
++      GST_DEBUG_OBJECT (src, "PAUSED->READY");
++      gst_ring_buffer_set_flushing (src->ringbuffer, TRUE);
++      break;
++    default:
++      break;
++  }
++
++  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
++
++  switch (transition) {
++    case GST_STATE_CHANGE_PAUSED_TO_READY:
++      GST_DEBUG_OBJECT (src, "PAUSED->READY");
++      gst_ring_buffer_release (src->ringbuffer);
++      break;
++    case GST_STATE_CHANGE_READY_TO_NULL:
++      GST_DEBUG_OBJECT (src, "READY->NULL");
++      gst_ring_buffer_close_device (src->ringbuffer);
++      GST_OBJECT_LOCK (src);
++      gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer));
++      src->ringbuffer = NULL;
++      GST_OBJECT_UNLOCK (src);
++      break;
++    default:
++      break;
++  }
++
++  return ret;
++
++  /* ERRORS */
++open_failed:
++  {
++    /* subclass must post a meaningfull error message */
++    GST_DEBUG_OBJECT (src, "open failed");
++    return GST_STATE_CHANGE_FAILURE;
++  }
++
++}
index 0000000,0000000..773c6e8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,127 @@@
++*************** gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
++*** 865,935 ****
++          running_time_segment = running_time_sample / sps;
++  
++          /* the segment currently read from the ringbuffer */
++-         current_segment = sample / sps;
++- 
++-         /* the skew we have between running_time and the ringbuffertime */
++-         segment_skew = running_time_segment - current_segment;
++- 
++-         GST_DEBUG_OBJECT (bsrc, "\n running_time = %" GST_TIME_FORMAT
++-             "\n timestamp     = %" GST_TIME_FORMAT
++-             "\n running_time_segment = %d"
++-             "\n current_segment      = %d"
++-             "\n segment_skew         = %d",
++              GST_TIME_ARGS (running_time),
++              GST_TIME_ARGS (timestamp),
++-             running_time_segment, current_segment, segment_skew);
++  
++          /* Resync the ringbuffer if:
++-          * 1. We are more than the length of the ringbuffer in front.
++-          *    The length of the ringbuffer then gets to dictate
++-          *    the threshold for what is concidered "too far ahead"
++-          *
++-          * 2. We are more than the length of the ringbuffer behind.
++           *    The length of the ringbuffer then gets to dictate
++           *    the threshold for what is concidered "too late"
++           *
++-          * 3. If this is our first buffer.
++           *    We know that we should catch up to running_time
++           *    the first time we are ran.
++           */
++-         if ((segment_skew <= -ringbuffer->spec.segtotal) ||
++-             (segment_skew >= ringbuffer->spec.segtotal) ||
++-             (current_segment == 0)) {
++-           gint segments_written;
++-           gint first_segment;
++-           gint last_segment;
++-           gint new_last_segment;
++            gint segment_diff;
++-           gint new_first_segment;
++            guint64 new_sample;
++  
++-           /* we are going to say that the last segment was captured at the current time
++-              (running_time), minus one segment of creation-latency in the ringbuffer.
++-              This can be thought of as: The segment arrived in the ringbuffer at time X, and
++-              that means it was created at time X - (one segment). */
++-           new_last_segment = running_time_segment - 1;
++- 
++-           /* for better readablity */
++-           first_segment = current_segment;
++- 
++-           /* get the amount of segments written from the device by now */
++-           segments_written = g_atomic_int_get (&ringbuffer->segdone);
++- 
++-           /* subtract the base to segments_written to get the number of the
++-              last written segment in the ringbuffer (one segment written = segment 0) */
++-           last_segment = segments_written - ringbuffer->segbase - 1;
++- 
++-           /* we see how many segments the ringbuffer was timeshifted */
++-           segment_diff = new_last_segment - last_segment;
++  
++-           /* we move the first segment an equal amount */
++-           new_first_segment = first_segment + segment_diff;
++  
++-           /* and we also move the segmentbase the same amount */
++-           ringbuffer->segbase -= segment_diff;
++  
++            /* we calculate the new sample value */
++-           new_sample = ((guint64) new_first_segment) * sps;
++  
++            /* and get the relative time to this -> our new timestamp */
++            timestamp =
++--- 874,926 ----
++          running_time_segment = running_time_sample / sps;
++  
++          /* the segment currently read from the ringbuffer */
+++         last_read_segment = sample / sps;
+++ 
+++         /* the skew we have between running_time and the ringbuffertime (last written to) */
+++         segment_skew = running_time_segment - last_written_segment;
+++ 
+++         GST_DEBUG_OBJECT (bsrc,
+++              "\n running_time                                              = %" GST_TIME_FORMAT
+++             "\n timestamp                                                  = %" GST_TIME_FORMAT
+++             "\n running_time_segment                                       = %d"
+++             "\n last_written_segment                                       = %d"
+++             "\n segment_skew (running time segment - last_written_segment) = %d"
+++             "\n last_read_segment                                          = %d",
++              GST_TIME_ARGS (running_time),
++              GST_TIME_ARGS (timestamp),
+++             running_time_segment,
+++             last_written_segment,
+++             segment_skew,
+++             last_read_segment);
++  
++          /* Resync the ringbuffer if:
+++ 
+++          * 1. We are more than the length of the ringbuffer behind.
++           *    The length of the ringbuffer then gets to dictate
++           *    the threshold for what is concidered "too late"
++           *
+++          * 2. If this is our first buffer.
++           *    We know that we should catch up to running_time
++           *    the first time we are ran.
++           */
+++         if ((segment_skew >= ringbuffer->spec.segtotal) ||
+++             (last_read_segment == 0))
+++         {
+++           gint new_read_segment;
++            gint segment_diff;
++            guint64 new_sample;
++  
+++           /* the difference between running_time and the last written segment */
+++           segment_diff = running_time_segment - last_written_segment;
++  
+++           /* advance the ringbuffer */
+++           gst_ring_buffer_advance(ringbuffer, segment_diff);
++  
+++            /* we move the  new read segment to the last known written segment */
+++           new_read_segment = g_atomic_int_get (&ringbuffer->segdone) - ringbuffer->segbase;
++  
++            /* we calculate the new sample value */
+++           new_sample = ((guint64) new_read_segment) * sps;
++  
++            /* and get the relative time to this -> our new timestamp */
++            timestamp =
index 0000000,0000000..6d23e19
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,362 @@@
++/* GStreamer
++ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
++ *                    2005 Wim Taymans <wim@fluendo.com>
++ *
++ * gstaudioringbuffer.c: simple audio ringbuffer base class
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++
++#include <string.h>
++
++#include "gstringbufferthread.h"
++
++GST_DEBUG_CATEGORY_STATIC (gst_ring_buffer_thread_debug);
++#define GST_CAT_DEFAULT gst_ring_buffer_thread_debug
++
++static void gst_ring_buffer_thread_class_init (GstRingBufferThreadClass *
++    klass);
++static void gst_ring_buffer_thread_init (GstRingBufferThread * ringbuffer,
++    GstRingBufferThreadClass * klass);
++static void gst_ring_buffer_thread_dispose (GObject * object);
++static void gst_ring_buffer_thread_finalize (GObject * object);
++
++static GstRingBufferClass *ring_parent_class = NULL;
++
++GType
++gst_ring_buffer_thread_get_type (void)
++{
++  static GType ringbuffer_type = 0;
++
++  if (!ringbuffer_type) {
++    static const GTypeInfo ringbuffer_info = {
++      sizeof (GstRingBufferThreadClass),
++      NULL,
++      NULL,
++      (GClassInitFunc) gst_ring_buffer_thread_class_init,
++      NULL,
++      NULL,
++      sizeof (GstRingBufferThread),
++      0,
++      (GInstanceInitFunc) gst_ring_buffer_thread_init,
++      NULL
++    };
++
++    ringbuffer_type =
++        g_type_register_static (GST_TYPE_OBJECT, "GstRingBufferThread",
++        &ringbuffer_info, 0);
++
++    GST_DEBUG_CATEGORY_INIT (gst_ring_buffer_thread_debug, "ringbufferthread",
++        0, "ringbuffer thread");
++  }
++  return ringbuffer_type;
++}
++
++static void
++gst_ring_buffer_thread_class_init (GstRingBufferThreadClass * klass)
++{
++  GObjectClass *gobject_class;
++
++  gobject_class = (GObjectClass *) klass;
++
++  ring_parent_class = g_type_class_peek_parent (klass);
++
++  gobject_class->dispose = gst_ring_buffer_thread_dispose;
++  gobject_class->finalize = gst_ring_buffer_thread_finalize;
++}
++
++typedef gint (*ProcessFunc) (GstAudioRingBuffer * buf, gpointer data,
++    guint length);
++
++/* this internal thread does nothing else but write samples to the audio device.
++ * It will write each segment in the ringbuffer and will update the play
++ * pointer.
++ * The start/stop methods control the thread.
++ */
++static void
++ring_buffer_thread_thread_func (GstRingBufferThread * thread)
++{
++  GstElement *parent = NULL;
++  GstMessage *message;
++  GValue val = { 0 };
++  GstAudioRingBuffer *capture, *playback;
++  ProcessFunc writefunc = NULL, readfunc = NULL;
++  gint preroll = 1;
++
++  GST_DEBUG_OBJECT (thread, "enter thread");
++
++  GST_OBJECT_LOCK (thread);
++  GST_DEBUG_OBJECT (thread, "signal wait");
++  GST_RING_BUFFER_THREAD_SIGNAL (thread);
++  if ((capture = thread->capture))
++    gst_object_ref (capture);
++  if ((playback = thread->playback))
++    gst_object_ref (playback);
++  GST_OBJECT_UNLOCK (thread);
++
++  if (capture)
++    readfunc = GST_AUDIO_RING_BUFFER_GET_CLASS (capture)->process;
++  if (playback)
++    writefunc = GST_AUDIO_RING_BUFFER_GET_CLASS (playback)->process;
++
++  if (parent) {
++    g_value_init (&val, G_TYPE_POINTER);
++    g_value_set_pointer (&val, thread->thread);
++    message = gst_message_new_stream_status (GST_OBJECT_CAST (thread),
++        GST_STREAM_STATUS_TYPE_ENTER, NULL);
++    gst_message_set_stream_status_object (message, &val);
++    GST_DEBUG_OBJECT (thread, "posting ENTER stream status");
++    gst_element_post_message (parent, message);
++  }
++
++  while (TRUE) {
++    gint left, processed;
++    guint8 *read_ptr, *write_ptr;
++    gint read_seg, write_seg;
++    gint read_len, write_len;
++    gboolean read_active, write_active;
++
++    if (playback)
++      write_active =
++          gst_ring_buffer_prepare_read (GST_RING_BUFFER_CAST (playback),
++          &write_seg, &write_ptr, &write_len);
++    else
++      write_active = FALSE;
++
++    if (playback) {
++      if (!write_active) {
++        write_ptr = GST_RING_BUFFER_CAST (playback)->empty_seg;
++        write_len = GST_RING_BUFFER_CAST (playback)->spec.segsize;
++      }
++
++      left = write_len;
++      do {
++        processed = writefunc (playback, write_ptr, left);
++        GST_LOG_OBJECT (thread, "written %d bytes of %d from segment %d",
++            processed, left, write_seg);
++        if (processed < 0 || processed > left) {
++          /* might not be critical, it e.g. happens when aborting playback */
++          GST_WARNING_OBJECT (thread,
++              "error writing data in %s (reason: %s), skipping segment (left: %d, processed: %d)",
++              GST_DEBUG_FUNCPTR_NAME (writefunc),
++              (errno > 1 ? g_strerror (errno) : "unknown"), left, processed);
++          break;
++        }
++        left -= processed;
++        write_ptr += processed;
++      } while (left > 0);
++
++      /* we wrote one segment */
++      gst_ring_buffer_advance (GST_RING_BUFFER_CAST (playback), 1);
++
++      if (preroll > 0) {
++        /* do not start reading until we have read enough data */
++        preroll--;
++        GST_DEBUG_OBJECT (thread, "need more preroll");
++        continue;
++      }
++    }
++
++
++    if (capture)
++      read_active =
++          gst_ring_buffer_prepare_read (GST_RING_BUFFER_CAST (capture),
++          &read_seg, &read_ptr, &read_len);
++    else
++      read_active = FALSE;
++
++    if (capture) {
++      left = read_len;
++      do {
++        processed = readfunc (capture, read_ptr, left);
++        GST_LOG_OBJECT (thread, "read %d bytes of %d from segment %d",
++            processed, left, read_seg);
++        if (processed < 0 || processed > left) {
++          /* might not be critical, it e.g. happens when aborting playback */
++          GST_WARNING_OBJECT (thread,
++              "error reading data in %s (reason: %s), skipping segment (left: %d, processed: %d)",
++              GST_DEBUG_FUNCPTR_NAME (readfunc),
++              (errno > 1 ? g_strerror (errno) : "unknown"), left, processed);
++          break;
++        }
++        left -= processed;
++        read_ptr += processed;
++      } while (left > 0);
++
++      if (read_active)
++        /* we read one segment */
++        gst_ring_buffer_advance (GST_RING_BUFFER_CAST (capture), 1);
++    }
++
++    if (!read_active && !write_active) {
++      GST_OBJECT_LOCK (thread);
++      if (!thread->running)
++        goto stop_running;
++      GST_DEBUG_OBJECT (thread, "signal wait");
++      GST_RING_BUFFER_THREAD_SIGNAL (thread);
++      GST_DEBUG_OBJECT (thread, "wait for action");
++      GST_RING_BUFFER_THREAD_WAIT (thread);
++      GST_DEBUG_OBJECT (thread, "got signal");
++      if (!thread->running)
++        goto stop_running;
++      GST_DEBUG_OBJECT (thread, "continue running");
++      GST_OBJECT_UNLOCK (thread);
++    }
++  }
++
++  /* Will never be reached */
++  g_assert_not_reached ();
++  return;
++
++  /* ERROR */
++stop_running:
++  {
++    GST_OBJECT_UNLOCK (thread);
++    GST_DEBUG_OBJECT (thread, "stop running, exit thread");
++    if (parent) {
++      message = gst_message_new_stream_status (GST_OBJECT_CAST (thread),
++          GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (thread));
++      gst_message_set_stream_status_object (message, &val);
++      GST_DEBUG_OBJECT (thread, "posting LEAVE stream status");
++      gst_element_post_message (parent, message);
++    }
++    return;
++  }
++}
++
++static void
++gst_ring_buffer_thread_init (GstRingBufferThread * thread,
++    GstRingBufferThreadClass * g_class)
++{
++  thread->running = FALSE;
++  thread->cond = g_cond_new ();
++}
++
++static void
++gst_ring_buffer_thread_dispose (GObject * object)
++{
++  GstRingBufferThread *thread = GST_RING_BUFFER_THREAD_CAST (object);
++
++  GST_OBJECT_LOCK (thread);
++  if (thread->playback) {
++    gst_object_unref (thread->playback);
++    thread->playback = NULL;
++  }
++  if (thread->capture) {
++    gst_object_unref (thread->capture);
++    thread->capture = NULL;
++  }
++  GST_OBJECT_UNLOCK (thread);
++
++  G_OBJECT_CLASS (ring_parent_class)->dispose (object);
++}
++
++static void
++gst_ring_buffer_thread_finalize (GObject * object)
++{
++  GstRingBufferThread *thread = GST_RING_BUFFER_THREAD_CAST (object);
++
++  g_cond_free (thread->cond);
++
++  G_OBJECT_CLASS (ring_parent_class)->finalize (object);
++}
++
++gboolean
++gst_ring_buffer_thread_activate (GstRingBufferThread * thread, gboolean active)
++{
++  GError *error = NULL;
++
++  GST_OBJECT_LOCK (thread);
++  if (active) {
++    if (thread->active_count == 0) {
++      thread->running = TRUE;
++      GST_DEBUG_OBJECT (thread, "starting thread");
++      thread->thread =
++          g_thread_create ((GThreadFunc) ring_buffer_thread_thread_func, thread,
++          TRUE, &error);
++      if (!thread->thread || error != NULL)
++        goto thread_failed;
++
++      GST_DEBUG_OBJECT (thread, "waiting for thread");
++      /* the object lock is taken */
++      GST_RING_BUFFER_THREAD_WAIT (thread);
++      GST_DEBUG_OBJECT (thread, "thread is started");
++    }
++    thread->active_count++;
++  } else {
++    if (thread->active_count == 1) {
++      thread->running = FALSE;
++      GST_DEBUG_OBJECT (thread, "signal wait");
++      GST_RING_BUFFER_THREAD_SIGNAL (thread);
++      GST_OBJECT_UNLOCK (thread);
++
++      /* join the thread */
++      g_thread_join (thread->thread);
++
++      GST_OBJECT_LOCK (thread);
++    }
++    thread->active_count--;
++  }
++  GST_OBJECT_UNLOCK (thread);
++
++  return TRUE;
++
++  /* ERRORS */
++thread_failed:
++  {
++    if (error)
++      GST_ERROR_OBJECT (thread, "could not create thread %s", error->message);
++    else
++      GST_ERROR_OBJECT (thread, "could not create thread for unknown reason");
++    thread->running = FALSE;
++    GST_OBJECT_UNLOCK (thread);
++    return FALSE;
++  }
++}
++
++gboolean
++gst_ring_buffer_thread_set_ringbuffer (GstRingBufferThread * thread,
++    GstAudioRingBuffer * buf)
++{
++  GstAudioRingBuffer *old, **new;
++
++  g_return_val_if_fail (GST_IS_RING_BUFFER_THREAD (thread), FALSE);
++
++  if (buf->mode == GST_AUDIO_RING_BUFFER_MODE_PLAYBACK)
++    new = &thread->playback;
++  else
++    new = &thread->capture;
++
++  old = *new;
++  if (buf)
++    gst_object_ref (buf);
++  *new = buf;
++  if (old)
++    gst_object_unref (old);
++
++  return TRUE;
++}
++
++gboolean
++gst_ring_buffer_thread_start (GstRingBufferThread * thread)
++{
++  g_return_val_if_fail (GST_IS_RING_BUFFER_THREAD (thread), FALSE);
++
++  GST_RING_BUFFER_THREAD_SIGNAL (thread);
++
++  return TRUE;
++}
index 0000000,0000000..70498c5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,93 @@@
++/* GStreamer
++ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
++ *                    2005 Wim Taymans <wim@fluendo.com>
++ *
++ * gstaudioringbuffer.h:
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __GST_RING_BUFFER_THREAD_H__
++#define __GST_RING_BUFFER_THREAD_H__
++
++#include <gst/gst.h>
++
++G_BEGIN_DECLS
++
++#define GST_TYPE_RING_BUFFER_THREAD             (gst_ring_buffer_thread_get_type())
++#define GST_RING_BUFFER_THREAD(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RING_BUFFER_THREAD,GstRingBufferThread))
++#define GST_RING_BUFFER_THREAD_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RING_BUFFER_THREAD,GstRingBufferThreadClass))
++#define GST_RING_BUFFER_THREAD_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_RING_BUFFER_THREAD,GstRingBufferThreadClass))
++#define GST_IS_RING_BUFFER_THREAD(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RING_BUFFER_THREAD))
++#define GST_IS_RING_BUFFER_THREAD_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RING_BUFFER_THREAD))
++#define GST_RING_BUFFER_THREAD_CAST(obj)        ((GstRingBufferThread *)obj)
++
++typedef struct _GstRingBufferThread GstRingBufferThread;
++typedef struct _GstRingBufferThreadClass GstRingBufferThreadClass;
++
++#include <gst/audio/gstaudioringbuffer.h>
++
++#define GST_RING_BUFFER_THREAD_GET_COND(buf) (((GstRingBufferThread *)buf)->cond)
++#define GST_RING_BUFFER_THREAD_WAIT(buf)     (g_cond_wait (GST_RING_BUFFER_THREAD_GET_COND (buf), GST_OBJECT_GET_LOCK (buf)))
++#define GST_RING_BUFFER_THREAD_SIGNAL(buf)   (g_cond_signal (GST_RING_BUFFER_THREAD_GET_COND (buf)))
++#define GST_RING_BUFFER_THREAD_BROADCAST(buf)(g_cond_broadcast (GST_RING_BUFFER_THREAD_GET_COND (buf)))
++
++/**
++ * GstRingBufferThread:
++ *
++ * Opaque #GstRingBufferThread.
++ */
++struct _GstRingBufferThread {
++  GstObject       parent;
++
++  gint       active_count;
++
++  /*< private >*/ /* with LOCK */
++  GThread   *thread;
++  gboolean   running;
++  GCond     *cond;
++
++  GstAudioRingBuffer *playback;
++  GstAudioRingBuffer *capture;
++
++  /*< private >*/
++  gpointer _gst_reserved[GST_PADDING];
++};
++
++/**
++ * GstRingBufferThreadClass:
++ * @parent_class: the parent class structure.
++ *
++ * #GstRingBufferThread class. Override the vmethods to implement functionality.
++ */
++struct _GstRingBufferThreadClass {
++  GstObjectClass parent_class;
++
++  /*< private >*/
++  gpointer _gst_reserved[GST_PADDING];
++};
++
++GType gst_ring_buffer_thread_get_type(void);
++
++gboolean gst_ring_buffer_thread_set_ringbuffer (GstRingBufferThread *thread, GstAudioRingBuffer *buf);
++
++gboolean gst_ring_buffer_thread_activate (GstRingBufferThread *thread, gboolean active);
++
++gboolean gst_ring_buffer_thread_start (GstRingBufferThread *thread);
++
++G_END_DECLS
++
++#endif /* __GST_RING_BUFFER_THREAD_H__ */
index 0000000,0000000..0a2041a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,617 @@@
++? foo
++Index: Makefile.am
++===================================================================
++RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/cdda/Makefile.am,v
++retrieving revision 1.4
++diff -u -p -u -p -r1.4 Makefile.am
++--- Makefile.am       3 Apr 2008 06:39:27 -0000       1.4
+++++ Makefile.am       21 Aug 2008 14:17:21 -0000
++@@ -1,9 +1,7 @@
++ lib_LTLIBRARIES = libgstcdda-@GST_MAJORMINOR@.la
++ 
++ libgstcdda_@GST_MAJORMINOR@_la_SOURCES = \
++-     gstcddabasesrc.c \
++-     sha1.c \
++-     sha1.h
+++     gstcddabasesrc.c
++ 
++ libgstcdda_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/cdda
++ libgstcdda_@GST_MAJORMINOR@include_HEADERS = \
++Index: gstcddabasesrc.c
++===================================================================
++RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/cdda/gstcddabasesrc.c,v
++retrieving revision 1.19
++diff -u -p -u -p -r1.19 gstcddabasesrc.c
++--- gstcddabasesrc.c  28 May 2008 15:48:33 -0000      1.19
+++++ gstcddabasesrc.c  21 Aug 2008 14:17:21 -0000
++@@ -1084,36 +1084,35 @@ cddb_sum (gint n)
++   return ret;
++ }
++ 
++-#include "sha1.h"
++-
++ static void
++ gst_cddabasesrc_calculate_musicbrainz_discid (GstCddaBaseSrc * src)
++ {
++   GString *s;
++-  SHA_INFO sha;
+++  GChecksum *sha;
++   guchar digest[20];
++   gchar *ptr;
++   gchar tmp[9];
++   gulong i;
++   guint leadout_sector;
+++  gsize digest_len;
++ 
++   s = g_string_new (NULL);
++ 
++   leadout_sector = src->tracks[src->num_tracks - 1].end + 1 + CD_MSF_OFFSET;
++ 
++   /* generate SHA digest */
++-  sha_init (&sha);
+++  sha = g_checksum_new (G_CHECKSUM_SHA1);
++   g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[0].num);
++   g_string_append_printf (s, "%02X", src->tracks[0].num);
++-  sha_update (&sha, (SHA_BYTE *) tmp, 2);
+++  g_checksum_update (sha, (guchar *) tmp, 2);
++ 
++   g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[src->num_tracks - 1].num);
++   g_string_append_printf (s, " %02X", src->tracks[src->num_tracks - 1].num);
++-  sha_update (&sha, (SHA_BYTE *) tmp, 2);
+++  g_checksum_update (sha, (guchar *) tmp, 2);
++ 
++   g_snprintf (tmp, sizeof (tmp), "%08X", leadout_sector);
++   g_string_append_printf (s, " %08X", leadout_sector);
++-  sha_update (&sha, (SHA_BYTE *) tmp, 8);
+++  g_checksum_update (sha, (guchar *) tmp, 8);
++ 
++   for (i = 0; i < 99; i++) {
++     if (i < src->num_tracks) {
++@@ -1121,15 +1120,17 @@ gst_cddabasesrc_calculate_musicbrainz_di
++ 
++       g_snprintf (tmp, sizeof (tmp), "%08X", frame_offset);
++       g_string_append_printf (s, " %08X", frame_offset);
++-      sha_update (&sha, (SHA_BYTE *) tmp, 8);
+++      g_checksum_update (sha, (guchar *) tmp, 8);
++     } else {
++-      sha_update (&sha, (SHA_BYTE *) "00000000", 8);
+++      g_checksum_update (sha, (guchar *) "00000000", 8);
++     }
++   }
++-  sha_final (digest, &sha);
+++  digest_len = 20;
+++  g_checksum_get_digest (sha, (guint8 *) &digest, &digest_len);
++ 
++   /* re-encode to base64 */
++-  ptr = g_base64_encode (digest, 20);
+++  ptr = g_base64_encode (digest, digest_len);
+++  g_checksum_free (sha);
++   i = strlen (ptr);
++ 
++   g_assert (i < sizeof (src->mb_discid) + 1);
++Index: sha1.c
++===================================================================
++RCS file: sha1.c
++diff -N sha1.c
++--- sha1.c    27 Feb 2008 10:42:08 -0000      1.2
+++++ /dev/null 1 Jan 1970 00:00:00 -0000
++@@ -1,450 +0,0 @@
++-/* (PD) 2001 The Bitzi Corporation
++- * Please see file COPYING or http://bitzi.com/publicdomain 
++- * for more info.
++- *
++- * NIST Secure Hash Algorithm 
++- * heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> 
++- * from Peter C. Gutmann's implementation as found in 
++- * Applied Cryptography by Bruce Schneier 
++- * Further modifications to include the "UNRAVEL" stuff, below 
++- *
++- * This code is in the public domain 
++- *
++- * $Id: sha1.c,v 1.2 2008-02-27 10:42:08 slomo Exp $
++- */
++-
++-#ifdef HAVE_CONFIG_H
++-#include "config.h"
++-#endif
++-#include <glib.h>
++-#define SHA_BYTE_ORDER G_BYTE_ORDER
++-
++-#include <string.h>
++-#include "sha1.h"
++-
++-/* UNRAVEL should be fastest & biggest */
++-/* UNROLL_LOOPS should be just as big, but slightly slower */
++-/* both undefined should be smallest and slowest */
++-
++-#define UNRAVEL
++-/* #define UNROLL_LOOPS */
++-
++-/* SHA f()-functions */
++-
++-#define f1(x,y,z)    ((x & y) | (~x & z))
++-#define f2(x,y,z)    (x ^ y ^ z)
++-#define f3(x,y,z)    ((x & y) | (x & z) | (y & z))
++-#define f4(x,y,z)    (x ^ y ^ z)
++-
++-/* SHA constants */
++-
++-#define CONST1               0x5a827999L
++-#define CONST2               0x6ed9eba1L
++-#define CONST3               0x8f1bbcdcL
++-#define CONST4               0xca62c1d6L
++-
++-/* truncate to 32 bits -- should be a null op on 32-bit machines */
++-
++-#define T32(x)       ((x) & 0xffffffffL)
++-
++-/* 32-bit rotate */
++-
++-#define R32(x,n)     T32(((x << n) | (x >> (32 - n))))
++-
++-/* the generic case, for when the overall rotation is not unraveled */
++-
++-#define FG(n)        \
++-    T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n);  \
++-    E = D; D = C; C = R32(B,30); B = A; A = T
++-
++-/* specific cases, for when the overall rotation is unraveled */
++-
++-#define FA(n)        \
++-    T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30)
++-
++-#define FB(n)        \
++-    E = T32(R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n); A = R32(A,30)
++-
++-#define FC(n)        \
++-    D = T32(R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n); T = R32(T,30)
++-
++-#define FD(n)        \
++-    C = T32(R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n); E = R32(E,30)
++-
++-#define FE(n)        \
++-    B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30)
++-
++-#define FT(n)        \
++-    A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30)
++-
++-/* do SHA transformation */
++-
++-static void
++-sha_transform (SHA_INFO * sha_info)
++-{
++-  int i;
++-  SHA_BYTE *dp;
++-  SHA_LONG T, A, B, C, D, E, W[80], *WP;
++-
++-  dp = sha_info->data;
++-
++-/*
++-the following makes sure that at least one code block below is
++-traversed or an error is reported, without the necessity for nested
++-preprocessor if/else/endif blocks, which are a great pain in the
++-nether regions of the anatomy...
++-*/
++-#undef SWAP_DONE
++-
++-#if (SHA_BYTE_ORDER == 1234)
++-#define SWAP_DONE
++-  for (i = 0; i < 16; ++i) {
++-    memcpy (&T, dp, sizeof (SHA_LONG));
++-    dp += 4;
++-    W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
++-        ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
++-  }
++-#endif /* SHA_BYTE_ORDER == 1234 */
++-
++-#if (SHA_BYTE_ORDER == 4321)
++-#define SWAP_DONE
++-  for (i = 0; i < 16; ++i) {
++-    memcpy (&T, dp, sizeof (SHA_LONG));
++-    dp += 4;
++-    W[i] = T32 (T);
++-  }
++-#endif /* SHA_BYTE_ORDER == 4321 */
++-
++-#if (SHA_BYTE_ORDER == 12345678)
++-#define SWAP_DONE
++-  for (i = 0; i < 16; i += 2) {
++-    memcpy (&T, dp, sizeof (SHA_LONG));
++-    dp += 8;
++-    W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
++-        ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
++-    T >>= 32;
++-    W[i + 1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
++-        ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
++-  }
++-#endif /* SHA_BYTE_ORDER == 12345678 */
++-
++-#if (SHA_BYTE_ORDER == 87654321)
++-#define SWAP_DONE
++-  for (i = 0; i < 16; i += 2) {
++-    memcpy (&T, dp, sizeof (SHA_LONG));
++-    dp += 8;
++-    W[i] = T32 (T >> 32);
++-    W[i + 1] = T32 (T);
++-  }
++-#endif /* SHA_BYTE_ORDER == 87654321 */
++-
++-#ifndef SWAP_DONE
++-#error Unknown byte order -- you need to add code here
++-#endif /* SWAP_DONE */
++-
++-  for (i = 16; i < 80; ++i) {
++-    W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
++-#if (SHA_VERSION == 1)
++-    W[i] = R32 (W[i], 1);
++-#endif /* SHA_VERSION */
++-  }
++-  A = sha_info->digest[0];
++-  B = sha_info->digest[1];
++-  C = sha_info->digest[2];
++-  D = sha_info->digest[3];
++-  E = sha_info->digest[4];
++-  WP = W;
++-#ifdef UNRAVEL
++-  FA (1);
++-  FB (1);
++-  FC (1);
++-  FD (1);
++-  FE (1);
++-  FT (1);
++-  FA (1);
++-  FB (1);
++-  FC (1);
++-  FD (1);
++-  FE (1);
++-  FT (1);
++-  FA (1);
++-  FB (1);
++-  FC (1);
++-  FD (1);
++-  FE (1);
++-  FT (1);
++-  FA (1);
++-  FB (1);
++-  FC (2);
++-  FD (2);
++-  FE (2);
++-  FT (2);
++-  FA (2);
++-  FB (2);
++-  FC (2);
++-  FD (2);
++-  FE (2);
++-  FT (2);
++-  FA (2);
++-  FB (2);
++-  FC (2);
++-  FD (2);
++-  FE (2);
++-  FT (2);
++-  FA (2);
++-  FB (2);
++-  FC (2);
++-  FD (2);
++-  FE (3);
++-  FT (3);
++-  FA (3);
++-  FB (3);
++-  FC (3);
++-  FD (3);
++-  FE (3);
++-  FT (3);
++-  FA (3);
++-  FB (3);
++-  FC (3);
++-  FD (3);
++-  FE (3);
++-  FT (3);
++-  FA (3);
++-  FB (3);
++-  FC (3);
++-  FD (3);
++-  FE (3);
++-  FT (3);
++-  FA (4);
++-  FB (4);
++-  FC (4);
++-  FD (4);
++-  FE (4);
++-  FT (4);
++-  FA (4);
++-  FB (4);
++-  FC (4);
++-  FD (4);
++-  FE (4);
++-  FT (4);
++-  FA (4);
++-  FB (4);
++-  FC (4);
++-  FD (4);
++-  FE (4);
++-  FT (4);
++-  FA (4);
++-  FB (4);
++-  sha_info->digest[0] = T32 (sha_info->digest[0] + E);
++-  sha_info->digest[1] = T32 (sha_info->digest[1] + T);
++-  sha_info->digest[2] = T32 (sha_info->digest[2] + A);
++-  sha_info->digest[3] = T32 (sha_info->digest[3] + B);
++-  sha_info->digest[4] = T32 (sha_info->digest[4] + C);
++-#else /* !UNRAVEL */
++-#ifdef UNROLL_LOOPS
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (1);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (2);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (3);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-  FG (4);
++-#else /* !UNROLL_LOOPS */
++-  for (i = 0; i < 20; ++i) {
++-    FG (1);
++-  }
++-  for (i = 20; i < 40; ++i) {
++-    FG (2);
++-  }
++-  for (i = 40; i < 60; ++i) {
++-    FG (3);
++-  }
++-  for (i = 60; i < 80; ++i) {
++-    FG (4);
++-  }
++-#endif /* !UNROLL_LOOPS */
++-  sha_info->digest[0] = T32 (sha_info->digest[0] + A);
++-  sha_info->digest[1] = T32 (sha_info->digest[1] + B);
++-  sha_info->digest[2] = T32 (sha_info->digest[2] + C);
++-  sha_info->digest[3] = T32 (sha_info->digest[3] + D);
++-  sha_info->digest[4] = T32 (sha_info->digest[4] + E);
++-#endif /* !UNRAVEL */
++-}
++-
++-/* initialize the SHA digest */
++-
++-void
++-sha_init (SHA_INFO * sha_info)
++-{
++-  sha_info->digest[0] = 0x67452301L;
++-  sha_info->digest[1] = 0xefcdab89L;
++-  sha_info->digest[2] = 0x98badcfeL;
++-  sha_info->digest[3] = 0x10325476L;
++-  sha_info->digest[4] = 0xc3d2e1f0L;
++-  sha_info->count_lo = 0L;
++-  sha_info->count_hi = 0L;
++-  sha_info->local = 0;
++-}
++-
++-/* update the SHA digest */
++-
++-void
++-sha_update (SHA_INFO * sha_info, SHA_BYTE * buffer, int count)
++-{
++-  int i;
++-  SHA_LONG clo;
++-
++-  clo = T32 (sha_info->count_lo + ((SHA_LONG) count << 3));
++-  if (clo < sha_info->count_lo) {
++-    ++sha_info->count_hi;
++-  }
++-  sha_info->count_lo = clo;
++-  sha_info->count_hi += (SHA_LONG) count >> 29;
++-  if (sha_info->local) {
++-    i = SHA_BLOCKSIZE - sha_info->local;
++-    if (i > count) {
++-      i = count;
++-    }
++-    memcpy (((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i);
++-    count -= i;
++-    buffer += i;
++-    sha_info->local += i;
++-    if (sha_info->local == SHA_BLOCKSIZE) {
++-      sha_transform (sha_info);
++-    } else {
++-      return;
++-    }
++-  }
++-  while (count >= SHA_BLOCKSIZE) {
++-    memcpy (sha_info->data, buffer, SHA_BLOCKSIZE);
++-    buffer += SHA_BLOCKSIZE;
++-    count -= SHA_BLOCKSIZE;
++-    sha_transform (sha_info);
++-  }
++-  memcpy (sha_info->data, buffer, count);
++-  sha_info->local = count;
++-}
++-
++-/* finish computing the SHA digest */
++-
++-void
++-sha_final (unsigned char digest[20], SHA_INFO * sha_info)
++-{
++-  int count;
++-  SHA_LONG lo_bit_count, hi_bit_count;
++-
++-  lo_bit_count = sha_info->count_lo;
++-  hi_bit_count = sha_info->count_hi;
++-  count = (int) ((lo_bit_count >> 3) & 0x3f);
++-  ((SHA_BYTE *) sha_info->data)[count++] = 0x80;
++-  if (count > SHA_BLOCKSIZE - 8) {
++-    memset (((SHA_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count);
++-    sha_transform (sha_info);
++-    memset ((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8);
++-  } else {
++-    memset (((SHA_BYTE *) sha_info->data) + count, 0,
++-        SHA_BLOCKSIZE - 8 - count);
++-  }
++-  sha_info->data[56] = (unsigned char) ((hi_bit_count >> 24) & 0xff);
++-  sha_info->data[57] = (unsigned char) ((hi_bit_count >> 16) & 0xff);
++-  sha_info->data[58] = (unsigned char) ((hi_bit_count >> 8) & 0xff);
++-  sha_info->data[59] = (unsigned char) ((hi_bit_count >> 0) & 0xff);
++-  sha_info->data[60] = (unsigned char) ((lo_bit_count >> 24) & 0xff);
++-  sha_info->data[61] = (unsigned char) ((lo_bit_count >> 16) & 0xff);
++-  sha_info->data[62] = (unsigned char) ((lo_bit_count >> 8) & 0xff);
++-  sha_info->data[63] = (unsigned char) ((lo_bit_count >> 0) & 0xff);
++-  sha_transform (sha_info);
++-  digest[0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff);
++-  digest[1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff);
++-  digest[2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff);
++-  digest[3] = (unsigned char) ((sha_info->digest[0]) & 0xff);
++-  digest[4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff);
++-  digest[5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff);
++-  digest[6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff);
++-  digest[7] = (unsigned char) ((sha_info->digest[1]) & 0xff);
++-  digest[8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff);
++-  digest[9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff);
++-  digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff);
++-  digest[11] = (unsigned char) ((sha_info->digest[2]) & 0xff);
++-  digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff);
++-  digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff);
++-  digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff);
++-  digest[15] = (unsigned char) ((sha_info->digest[3]) & 0xff);
++-  digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff);
++-  digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff);
++-  digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff);
++-  digest[19] = (unsigned char) ((sha_info->digest[4]) & 0xff);
++-}
++Index: sha1.h
++===================================================================
++RCS file: sha1.h
++diff -N sha1.h
++--- sha1.h    13 Dec 2007 10:10:35 -0000      1.2
+++++ /dev/null 1 Jan 1970 00:00:00 -0000
++@@ -1,62 +0,0 @@
++-/* NIST Secure Hash Algorithm */
++-/* heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> */
++-/* from Peter C. Gutmann's implementation as found in */
++-/* Applied Cryptography by Bruce Schneier */
++-/* This code is in the public domain */
++-/* $Id: sha1.h,v 1.2 2007-12-13 10:10:35 tpm Exp $ */
++-
++-#ifndef __GST_CDDA_SHA_H__
++-#define __GST_CDDA_SHA_H__
++-
++-#include <stdlib.h>
++-#include <stdio.h>
++-
++-/* Useful defines & typedefs */
++-typedef unsigned char SHA_BYTE;      /* 8-bit quantity */
++-typedef unsigned long SHA_LONG;      /* 32-or-more-bit quantity */
++-
++-#define SHA_BLOCKSIZE                64
++-#define SHA_DIGESTSIZE               20
++-
++-typedef struct {
++-    SHA_LONG digest[5];              /* message digest */
++-    SHA_LONG count_lo, count_hi;     /* 64-bit bit count */
++-    SHA_BYTE data[SHA_BLOCKSIZE];    /* SHA data buffer */
++-    int local;                       /* unprocessed amount in data */
++-} SHA_INFO;
++-
++-#define sha_init   __gst_cdda_sha_init
++-#define sha_update __gst_cdda_sha_update
++-#define sha_final  __gst_cdda_sha_final
++-
++-void sha_init(SHA_INFO *);
++-void sha_update(SHA_INFO *, SHA_BYTE *, int);
++-void sha_final(unsigned char [20], SHA_INFO *);
++-
++-#define SHA_VERSION 1
++-
++-#ifdef HAVE_CONFIG_H 
++-#include "config.h"
++-
++-
++-#ifdef WORDS_BIGENDIAN
++-#  if SIZEOF_LONG == 4
++-#    define SHA_BYTE_ORDER  4321
++-#  elif SIZEOF_LONG == 8
++-#    define SHA_BYTE_ORDER  87654321
++-#  endif
++-#else
++-#  if SIZEOF_LONG == 4
++-#    define SHA_BYTE_ORDER  1234
++-#  elif SIZEOF_LONG == 8
++-#    define SHA_BYTE_ORDER  12345678
++-#  endif
++-#endif
++-
++-#else
++-
++-#define SHA_BYTE_ORDER 1234
++-
++-#endif
++-
++-#endif /* __GST_CDDA_SHA_H__ */
index 0000000,0000000..3a0bea8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1594 @@@
++/* GStreamer
++ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
++ * Copyright (C) 2005 Tim-Philipp Müller <tim centricular net>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/* TODO:
++ *
++ *  - in ::start(), we want to post a tags message with an array or a list
++ *    of tagslists of all tracks, so that applications know at least the
++ *    number of tracks and all track durations immediately without having
++ *    to do any querying. We have to decide what type and name to use for
++ *    this array of track taglists.
++ *
++ *  - FIX cddb discid calculation algorithm for mixed mode CDs - do we use
++ *    offsets and duration of ALL tracks (data + audio) for the CDDB ID
++ *    calculation, or only audio tracks?
++ *
++ *  - Do we really need properties for the TOC bias/offset stuff? Wouldn't
++ *    environment variables make much more sense? Do we need this at all
++ *    (does it only affect ancient hardware?)
++ */
++
++/**
++ * SECTION:gstcddabasesrc
++ * @short_description: Base class for CD digital audio (CDDA) sources
++ *
++ * <refsect2>
++ * <para>
++ * Provides a base class for CDDA sources, which handles things like seeking,
++ * querying, discid calculation, tags, and buffer timestamping.
++ * </para>
++ * <title>Using GstCddaBaseSrc-based elements in applications</title>
++ * <para>
++ * GstCddaBaseSrc registers two #GstFormat<!-- -->s of its own, namely
++ * the "track" format and the "sector" format. Applications will usually
++ * only find the "track" format interesting. You can retrieve that #GstFormat
++ * for use in seek events or queries with gst_format_get_by_nick("track").
++ * </para>
++ * <para>
++ * In order to query the number of tracks, for example, an application would
++ * set the CDDA source element to READY or PAUSED state and then query the
++ * the number of tracks via gst_element_query_duration() using the track
++ * format acquired above. Applications can query the currently playing track
++ * in the same way.
++ * </para>
++ * <para>
++ * Alternatively, applications may retrieve the currently playing track and
++ * the total number of tracks from the taglist that will posted on the bus
++ * whenever the CD is opened or the currently playing track changes. The
++ * taglist will contain GST_TAG_TRACK_NUMBER and GST_TAG_TRACK_COUNT tags.
++ * </para>
++ * <para>
++ * Applications playing back CD audio using playbin and cdda://n URIs should
++ * issue a seek command in track format to change between tracks, rather than
++ * setting a new cdda://n+1 URI on playbin (as setting a new URI on playbin
++ * involves closing and re-opening the CD device, which is much much slower).
++ * </para>
++ * <title>Tags and meta-information</title>
++ * <para>
++ * CDDA sources will automatically emit a number of tags, details about which
++ * can be found in the libgsttag documentation. Those tags are:
++ * #GST_TAG_CDDA_CDDB_DISCID, #GST_TAG_CDDA_CDDB_DISCID_FULL,
++ * #GST_TAG_CDDA_MUSICBRAINZ_DISCID, #GST_TAG_CDDA_MUSICBRAINZ_DISCID_FULL,
++ * among others.
++ * </para>
++ * </refsect2>
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <string.h>
++#include <stdlib.h>             /* for strtol */
++
++#include "gstcddabasesrc.h"
++#include "gst/gst-i18n-plugin.h"
++
++GST_DEBUG_CATEGORY_STATIC (gst_cdda_base_src_debug);
++#define GST_CAT_DEFAULT gst_cdda_base_src_debug
++
++#define DEFAULT_DEVICE                       "/dev/cdrom"
++
++#define CD_FRAMESIZE_RAW                     (2352)
++
++#define SECTORS_PER_SECOND                   (75)
++#define SECTORS_PER_MINUTE                   (75*60)
++#define SAMPLES_PER_SECTOR                   (CD_FRAMESIZE_RAW >> 2)
++#define TIME_INTERVAL_FROM_SECTORS(sectors)  ((SAMPLES_PER_SECTOR * sectors * GST_SECOND) / 44100)
++#define SECTORS_FROM_TIME_INTERVAL(dtime)    (dtime * 44100 / (SAMPLES_PER_SECTOR * GST_SECOND))
++
++enum
++{
++  ARG_0,
++  ARG_MODE,
++  ARG_DEVICE,
++  ARG_TRACK,
++  ARG_TOC_OFFSET,
++  ARG_TOC_BIAS
++};
++
++static void gst_cdda_base_src_get_property (GObject * object, guint prop_id,
++    GValue * value, GParamSpec * pspec);
++static void gst_cdda_base_src_set_property (GObject * object, guint prop_id,
++    const GValue * value, GParamSpec * pspec);
++static void gst_cdda_base_src_finalize (GObject * obj);
++static const GstQueryType *gst_cdda_base_src_get_query_types (GstPad * pad);
++static gboolean gst_cdda_base_src_query (GstBaseSrc * src, GstQuery * query);
++static gboolean gst_cdda_base_src_handle_event (GstBaseSrc * basesrc,
++    GstEvent * event);
++static gboolean gst_cdda_base_src_do_seek (GstBaseSrc * basesrc,
++    GstSegment * segment);
++static void gst_cdda_base_src_setup_interfaces (GType type);
++static gboolean gst_cdda_base_src_start (GstBaseSrc * basesrc);
++static gboolean gst_cdda_base_src_stop (GstBaseSrc * basesrc);
++static GstFlowReturn gst_cdda_base_src_create (GstPushSrc * pushsrc,
++    GstBuffer ** buf);
++static gboolean gst_cdda_base_src_is_seekable (GstBaseSrc * basesrc);
++static void gst_cdda_base_src_update_duration (GstCddaBaseSrc * src);
++static void gst_cdda_base_src_set_index (GstElement * src, GstIndex * index);
++static GstIndex *gst_cdda_base_src_get_index (GstElement * src);
++
++GST_BOILERPLATE_FULL (GstCddaBaseSrc, gst_cdda_base_src, GstPushSrc,
++    GST_TYPE_PUSH_SRC, gst_cdda_base_src_setup_interfaces);
++
++#define SRC_CAPS \
++  "audio/x-raw-int, "               \
++  "endianness = (int) BYTE_ORDER, " \
++  "signed = (boolean) true, "       \
++  "width = (int) 16, "              \
++  "depth = (int) 16, "              \
++  "rate = (int) 44100, "            \
++  "channels = (int) 2"              \
++
++static GstStaticPadTemplate gst_cdda_base_src_src_template =
++GST_STATIC_PAD_TEMPLATE ("src",
++    GST_PAD_SRC,
++    GST_PAD_ALWAYS,
++    GST_STATIC_CAPS (SRC_CAPS)
++    );
++
++/* our two formats */
++static GstFormat track_format;
++static GstFormat sector_format;
++
++GType
++gst_cdda_base_src_mode_get_type (void)
++{
++  static GType mode_type;       /* 0 */
++  static const GEnumValue modes[] = {
++    {GST_CDDA_BASE_SRC_MODE_NORMAL, "Stream consists of a single track",
++        "normal"},
++    {GST_CDDA_BASE_SRC_MODE_CONTINUOUS, "Stream consists of the whole disc",
++        "continuous"},
++    {0, NULL, NULL}
++  };
++
++  if (mode_type == 0)
++    mode_type = g_enum_register_static ("GstCddaBaseSrcMode", modes);
++
++  return mode_type;
++}
++
++static void
++gst_cdda_base_src_base_init (gpointer g_class)
++{
++  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
++
++  gst_element_class_add_pad_template (element_class,
++      gst_static_pad_template_get (&gst_cdda_base_src_src_template));
++
++  /* our very own formats */
++  track_format = gst_format_register ("track", "CD track");
++  sector_format = gst_format_register ("sector", "CD sector");
++
++  /* register CDDA tags */
++  gst_tag_register_musicbrainz_tags ();
++
++#if 0
++  ///// FIXME: what type to use here? ///////
++  gst_tag_register (GST_TAG_CDDA_TRACK_TAGS, GST_TAG_FLAG_META, GST_TYPE_TAG_LIST, "track-tags", "CDDA taglist for one track", gst_tag_merge_use_first);        ///////////// FIXME: right function??? ///////
++#endif
++
++  GST_DEBUG_CATEGORY_INIT (gst_cdda_base_src_debug, "cddabasesrc", 0,
++      "CDDA Base Source");
++}
++
++static void
++gst_cdda_base_src_class_init (GstCddaBaseSrcClass * klass)
++{
++  GstElementClass *element_class;
++  GstPushSrcClass *pushsrc_class;
++  GstBaseSrcClass *basesrc_class;
++  GObjectClass *gobject_class;
++
++  gobject_class = (GObjectClass *) klass;
++  element_class = (GstElementClass *) klass;
++  basesrc_class = (GstBaseSrcClass *) klass;
++  pushsrc_class = (GstPushSrcClass *) klass;
++
++  gobject_class->set_property = gst_cdda_base_src_set_property;
++  gobject_class->get_property = gst_cdda_base_src_get_property;
++  gobject_class->finalize = gst_cdda_base_src_finalize;
++
++  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE,
++      g_param_spec_string ("device", "Device", "CD device location",
++          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODE,
++      g_param_spec_enum ("mode", "Mode", "Mode", GST_TYPE_CDDA_BASE_SRC_MODE,
++          GST_CDDA_BASE_SRC_MODE_NORMAL,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++
++  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TRACK,
++      g_param_spec_uint ("track", "Track", "Track", 1, 99, 1,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++
++#if 0
++  /* Do we really need this toc adjustment stuff as properties? does the user
++   * have a chance to set it in practice, e.g. when using sound-juicer, rb,
++   * totem, whatever? Shouldn't we rather use environment variables
++   * for this? (tpm) */
++
++  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_OFFSET,
++      g_param_spec_int ("toc-offset", "Table of contents offset",
++          "Add <n> sectors to the values reported", G_MININT, G_MAXINT, 0,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_BIAS,
++      g_param_spec_boolean ("toc-bias", "Table of contents bias",
++          "Assume that the beginning offset of track 1 as reported in the TOC "
++          "will be addressed as LBA 0.  Necessary for some Toshiba drives to "
++          "get track boundaries", FALSE,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++#endif
++
++  element_class->set_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_set_index);
++  element_class->get_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_index);
++
++  basesrc_class->start = GST_DEBUG_FUNCPTR (gst_cdda_base_src_start);
++  basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_cdda_base_src_stop);
++  basesrc_class->query = GST_DEBUG_FUNCPTR (gst_cdda_base_src_query);
++  basesrc_class->event = GST_DEBUG_FUNCPTR (gst_cdda_base_src_handle_event);
++  basesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_cdda_base_src_do_seek);
++  basesrc_class->is_seekable =
++      GST_DEBUG_FUNCPTR (gst_cdda_base_src_is_seekable);
++
++  pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_cdda_base_src_create);
++}
++
++static void
++gst_cdda_base_src_init (GstCddaBaseSrc * src, GstCddaBaseSrcClass * klass)
++{
++  gst_pad_set_query_type_function (GST_BASE_SRC_PAD (src),
++      GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_query_types));
++
++  /* we're not live and we operate in time */
++  gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
++  gst_base_src_set_live (GST_BASE_SRC (src), FALSE);
++
++  src->device = NULL;
++  src->mode = GST_CDDA_BASE_SRC_MODE_NORMAL;
++  src->uri_track = -1;
++}
++
++static void
++gst_cdda_base_src_finalize (GObject * obj)
++{
++  GstCddaBaseSrc *cddasrc = GST_CDDA_BASE_SRC (obj);
++
++  g_free (cddasrc->uri);
++  g_free (cddasrc->device);
++
++  G_OBJECT_CLASS (parent_class)->finalize (obj);
++}
++
++static void
++gst_cdda_base_src_set_property (GObject * object, guint prop_id,
++    const GValue * value, GParamSpec * pspec)
++{
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (object);
++
++  GST_OBJECT_LOCK (src);
++
++  switch (prop_id) {
++    case ARG_MODE:{
++      src->mode = g_value_get_enum (value);
++      break;
++    }
++    case ARG_DEVICE:{
++      const gchar *dev = g_value_get_string (value);
++
++      g_free (src->device);
++      if (dev && *dev) {
++        src->device = g_strdup (dev);
++      } else {
++        src->device = NULL;
++      }
++      break;
++    }
++    case ARG_TRACK:{
++      guint track = g_value_get_uint (value);
++
++      if (src->num_tracks > 0 && track > src->num_tracks) {
++        g_warning ("Invalid track %u", track);
++      } else if (track > 0 && src->tracks != NULL) {
++        src->cur_sector = src->tracks[track - 1].start;
++        src->uri_track = track;
++      } else {
++        src->uri_track = track; /* seek will be done in start() */
++      }
++      break;
++    }
++    case ARG_TOC_OFFSET:{
++      src->toc_offset = g_value_get_int (value);
++      break;
++    }
++    case ARG_TOC_BIAS:{
++      src->toc_bias = g_value_get_boolean (value);
++      break;
++    }
++    default:{
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++    }
++  }
++
++  GST_OBJECT_UNLOCK (src);
++}
++
++static void
++gst_cdda_base_src_get_property (GObject * object, guint prop_id,
++    GValue * value, GParamSpec * pspec)
++{
++  GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (object);
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (object);
++
++  GST_OBJECT_LOCK (src);
++
++  switch (prop_id) {
++    case ARG_MODE:
++      g_value_set_enum (value, src->mode);
++      break;
++    case ARG_DEVICE:{
++      if (src->device == NULL && klass->get_default_device != NULL) {
++        gchar *d = klass->get_default_device (src);
++
++        if (d != NULL) {
++          g_value_set_string (value, DEFAULT_DEVICE);
++          g_free (d);
++          break;
++        }
++      }
++      if (src->device == NULL)
++        g_value_set_string (value, DEFAULT_DEVICE);
++      else
++        g_value_set_string (value, src->device);
++      break;
++    }
++    case ARG_TRACK:{
++      if (src->num_tracks <= 0 && src->uri_track > 0) {
++        g_value_set_uint (value, src->uri_track);
++      } else {
++        g_value_set_uint (value, src->cur_track + 1);
++      }
++      break;
++    }
++    case ARG_TOC_OFFSET:
++      g_value_set_int (value, src->toc_offset);
++      break;
++    case ARG_TOC_BIAS:
++      g_value_set_boolean (value, src->toc_bias);
++      break;
++    default:{
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++    }
++  }
++
++  GST_OBJECT_UNLOCK (src);
++}
++
++static gint
++gst_cdda_base_src_get_track_from_sector (GstCddaBaseSrc * src, gint sector)
++{
++  gint i;
++
++  for (i = 0; i < src->num_tracks; ++i) {
++    if (sector >= src->tracks[i].start && sector <= src->tracks[i].end)
++      return i;
++  }
++  return -1;
++}
++
++static const GstQueryType *
++gst_cdda_base_src_get_query_types (GstPad * pad)
++{
++  static const GstQueryType src_query_types[] = {
++    GST_QUERY_DURATION,
++    GST_QUERY_POSITION,
++    GST_QUERY_CONVERT,
++    0
++  };
++
++  return src_query_types;
++}
++
++static gboolean
++gst_cdda_base_src_convert (GstCddaBaseSrc * src, GstFormat src_format,
++    gint64 src_val, GstFormat dest_format, gint64 * dest_val)
++{
++  gboolean started;
++
++  GST_LOG_OBJECT (src, "converting value %" G_GINT64_FORMAT " from %s into %s",
++      src_val, gst_format_get_name (src_format),
++      gst_format_get_name (dest_format));
++
++  if (src_format == dest_format) {
++    *dest_val = src_val;
++    return TRUE;
++  }
++
++  started = GST_OBJECT_FLAG_IS_SET (GST_BASE_SRC (src), GST_BASE_SRC_STARTED);
++
++  if (src_format == track_format) {
++    if (!started)
++      goto not_started;
++    if (src_val < 0 || src_val >= src->num_tracks) {
++      GST_DEBUG_OBJECT (src, "track number %d out of bounds", (gint) src_val);
++      goto wrong_value;
++    }
++    src_format = GST_FORMAT_DEFAULT;
++    src_val = src->tracks[src_val].start * SAMPLES_PER_SECTOR;
++  } else if (src_format == sector_format) {
++    src_format = GST_FORMAT_DEFAULT;
++    src_val = src_val * SAMPLES_PER_SECTOR;
++  }
++
++  if (src_format == dest_format) {
++    *dest_val = src_val;
++    goto done;
++  }
++
++  switch (src_format) {
++    case GST_FORMAT_BYTES:
++      /* convert to samples (4 bytes per sample) */
++      src_val = src_val >> 2;
++      /* fallthrough */
++    case GST_FORMAT_DEFAULT:{
++      switch (dest_format) {
++        case GST_FORMAT_BYTES:{
++          if (src_val < 0) {
++            GST_DEBUG_OBJECT (src, "sample source value negative");
++            goto wrong_value;
++          }
++          *dest_val = src_val << 2;     /* 4 bytes per sample */
++          break;
++        }
++        case GST_FORMAT_TIME:{
++          *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, 44100);
++          break;
++        }
++        default:{
++          gint64 sector = src_val / SAMPLES_PER_SECTOR;
++
++          if (dest_format == sector_format) {
++            *dest_val = sector;
++          } else if (dest_format == track_format) {
++            if (!started)
++              goto not_started;
++            *dest_val = gst_cdda_base_src_get_track_from_sector (src, sector);
++          } else {
++            goto unknown_format;
++          }
++          break;
++        }
++      }
++      break;
++    }
++    case GST_FORMAT_TIME:{
++      gint64 sample_offset;
++
++      if (src_val == GST_CLOCK_TIME_NONE) {
++        GST_DEBUG_OBJECT (src, "source time value invalid");
++        goto wrong_value;
++      }
++
++      sample_offset = gst_util_uint64_scale_int (src_val, 44100, GST_SECOND);
++      switch (dest_format) {
++        case GST_FORMAT_BYTES:{
++          *dest_val = sample_offset << 2;       /* 4 bytes per sample */
++          break;
++        }
++        case GST_FORMAT_DEFAULT:{
++          *dest_val = sample_offset;
++          break;
++        }
++        default:{
++          gint64 sector = sample_offset / SAMPLES_PER_SECTOR;
++
++          if (dest_format == sector_format) {
++            *dest_val = sector;
++          } else if (dest_format == track_format) {
++            if (!started)
++              goto not_started;
++            *dest_val = gst_cdda_base_src_get_track_from_sector (src, sector);
++          } else {
++            goto unknown_format;
++          }
++          break;
++        }
++      }
++      break;
++    }
++    default:{
++      goto unknown_format;
++    }
++  }
++
++done:
++  {
++    GST_LOG_OBJECT (src, "returning %" G_GINT64_FORMAT, *dest_val);
++    return TRUE;
++  }
++
++unknown_format:
++  {
++    GST_DEBUG_OBJECT (src, "conversion failed: %s", "unsupported format");
++    return FALSE;
++  }
++
++wrong_value:
++  {
++    GST_DEBUG_OBJECT (src, "conversion failed: %s",
++        "source value not within allowed range");
++    return FALSE;
++  }
++
++not_started:
++  {
++    GST_DEBUG_OBJECT (src, "conversion failed: %s",
++        "cannot do this conversion, device not open");
++    return FALSE;
++  }
++}
++
++static gboolean
++gst_cdda_base_src_query (GstBaseSrc * basesrc, GstQuery * query)
++{
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
++  gboolean started;
++
++  started = GST_OBJECT_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED);
++
++  GST_LOG_OBJECT (src, "handling %s query",
++      gst_query_type_get_name (GST_QUERY_TYPE (query)));
++
++  switch (GST_QUERY_TYPE (query)) {
++    case GST_QUERY_DURATION:{
++      GstFormat dest_format;
++      gint64 dest_val;
++      guint sectors;
++
++      gst_query_parse_duration (query, &dest_format, NULL);
++
++      if (!started)
++        return FALSE;
++
++      g_assert (src->tracks != NULL);
++
++      if (dest_format == track_format) {
++        GST_LOG_OBJECT (src, "duration: %d tracks", src->num_tracks);
++        gst_query_set_duration (query, track_format, src->num_tracks);
++        return TRUE;
++      }
++
++      if (src->cur_track < 0 || src->cur_track >= src->num_tracks)
++        return FALSE;
++
++      if (src->mode == GST_CDDA_BASE_SRC_MODE_NORMAL) {
++        sectors = src->tracks[src->cur_track].end -
++            src->tracks[src->cur_track].start + 1;
++      } else {
++        sectors = src->tracks[src->num_tracks - 1].end -
++            src->tracks[0].start + 1;
++      }
++
++      /* ... and convert into final format */
++      if (!gst_cdda_base_src_convert (src, sector_format, sectors,
++              dest_format, &dest_val)) {
++        return FALSE;
++      }
++
++      gst_query_set_duration (query, dest_format, dest_val);
++
++      GST_LOG ("duration: %u sectors, %" G_GINT64_FORMAT " in format %s",
++          sectors, dest_val, gst_format_get_name (dest_format));
++      break;
++    }
++    case GST_QUERY_POSITION:{
++      GstFormat dest_format;
++      gint64 pos_sector;
++      gint64 dest_val;
++
++      gst_query_parse_position (query, &dest_format, NULL);
++
++      if (!started)
++        return FALSE;
++
++      g_assert (src->tracks != NULL);
++
++      if (dest_format == track_format) {
++        GST_LOG_OBJECT (src, "position: track %d", src->cur_track);
++        gst_query_set_position (query, track_format, src->cur_track);
++        return TRUE;
++      }
++
++      if (src->cur_track < 0 || src->cur_track >= src->num_tracks)
++        return FALSE;
++
++      if (src->mode == GST_CDDA_BASE_SRC_MODE_NORMAL) {
++        pos_sector = src->cur_sector - src->tracks[src->cur_track].start;
++      } else {
++        pos_sector = src->cur_sector - src->tracks[0].start;
++      }
++
++      if (!gst_cdda_base_src_convert (src, sector_format, pos_sector,
++              dest_format, &dest_val)) {
++        return FALSE;
++      }
++
++      gst_query_set_position (query, dest_format, dest_val);
++
++      GST_LOG ("position: sector %u, %" G_GINT64_FORMAT " in format %s",
++          (guint) pos_sector, dest_val, gst_format_get_name (dest_format));
++      break;
++    }
++    case GST_QUERY_CONVERT:{
++      GstFormat src_format, dest_format;
++      gint64 src_val, dest_val;
++
++      gst_query_parse_convert (query, &src_format, &src_val, &dest_format,
++          NULL);
++
++      if (!gst_cdda_base_src_convert (src, src_format, src_val, dest_format,
++              &dest_val)) {
++        return FALSE;
++      }
++
++      gst_query_set_convert (query, src_format, src_val, dest_format, dest_val);
++      break;
++    }
++    default:{
++      GST_DEBUG_OBJECT (src, "unhandled query, chaining up to parent class");
++      return GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
++    }
++  }
++
++  return TRUE;
++}
++
++static gboolean
++gst_cdda_base_src_is_seekable (GstBaseSrc * basesrc)
++{
++  return TRUE;
++}
++
++static gboolean
++gst_cdda_base_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment)
++{
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
++  gint64 seek_sector;
++
++  GST_DEBUG_OBJECT (src, "segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
++      GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop));
++
++  if (!gst_cdda_base_src_convert (src, GST_FORMAT_TIME, segment->start,
++          sector_format, &seek_sector)) {
++    GST_WARNING_OBJECT (src, "conversion failed");
++    return FALSE;
++  }
++
++  /* we should only really be called when open */
++  g_assert (src->cur_track >= 0 && src->cur_track < src->num_tracks);
++
++  switch (src->mode) {
++    case GST_CDDA_BASE_SRC_MODE_NORMAL:
++      seek_sector += src->tracks[src->cur_track].start;
++      break;
++    case GST_CDDA_BASE_SRC_MODE_CONTINUOUS:
++      seek_sector += src->tracks[0].start;
++      break;
++    default:
++      g_return_val_if_reached (FALSE);
++  }
++
++  src->cur_sector = (gint) seek_sector;
++
++  GST_DEBUG_OBJECT (src, "seek'd to sector %d", src->cur_sector);
++
++  return TRUE;
++}
++
++static gboolean
++gst_cdda_base_src_handle_track_seek (GstCddaBaseSrc * src, gdouble rate,
++    GstSeekFlags flags, GstSeekType start_type, gint64 start,
++    GstSeekType stop_type, gint64 stop)
++{
++  GstBaseSrc *basesrc = GST_BASE_SRC (src);
++  GstEvent *event;
++
++  if ((flags & GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) {
++    gint64 start_time = -1;
++    gint64 stop_time = -1;
++
++    if (src->mode != GST_CDDA_BASE_SRC_MODE_CONTINUOUS) {
++      GST_DEBUG_OBJECT (src, "segment seek in track format is only "
++          "supported in CONTINUOUS mode, not in mode %d", src->mode);
++      return FALSE;
++    }
++
++    switch (start_type) {
++      case GST_SEEK_TYPE_SET:
++        if (!gst_cdda_base_src_convert (src, track_format, start,
++                GST_FORMAT_TIME, &start_time)) {
++          GST_DEBUG_OBJECT (src, "cannot convert track %d to time",
++              (gint) start);
++          return FALSE;
++        }
++        break;
++      case GST_SEEK_TYPE_END:
++        if (!gst_cdda_base_src_convert (src, track_format,
++                src->num_tracks - start - 1, GST_FORMAT_TIME, &start_time)) {
++          GST_DEBUG_OBJECT (src, "cannot convert track %d to time",
++              (gint) start);
++          return FALSE;
++        }
++        start_type = GST_SEEK_TYPE_SET;
++        break;
++      case GST_SEEK_TYPE_NONE:
++        start_time = -1;
++        break;
++      default:
++        g_return_val_if_reached (FALSE);
++    }
++
++    switch (stop_type) {
++      case GST_SEEK_TYPE_SET:
++        if (!gst_cdda_base_src_convert (src, track_format, stop,
++                GST_FORMAT_TIME, &stop_time)) {
++          GST_DEBUG_OBJECT (src, "cannot convert track %d to time",
++              (gint) stop);
++          return FALSE;
++        }
++        break;
++      case GST_SEEK_TYPE_END:
++        if (!gst_cdda_base_src_convert (src, track_format,
++                src->num_tracks - stop - 1, GST_FORMAT_TIME, &stop_time)) {
++          GST_DEBUG_OBJECT (src, "cannot convert track %d to time",
++              (gint) stop);
++          return FALSE;
++        }
++        stop_type = GST_SEEK_TYPE_SET;
++        break;
++      case GST_SEEK_TYPE_NONE:
++        stop_time = -1;
++        break;
++      default:
++        g_return_val_if_reached (FALSE);
++    }
++
++    GST_LOG_OBJECT (src, "seek segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
++        GST_TIME_ARGS (start_time), GST_TIME_ARGS (stop_time));
++
++    /* send fake segment seek event in TIME format to
++     * base class, which will hopefully handle the rest */
++
++    event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, start_type,
++        start_time, stop_type, stop_time);
++
++    return GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
++  }
++
++  /* not a segment seek */
++
++  if (start_type == GST_SEEK_TYPE_NONE) {
++    GST_LOG_OBJECT (src, "start seek type is NONE, nothing to do");
++    return TRUE;
++  }
++
++  if (stop_type != GST_SEEK_TYPE_NONE) {
++    GST_WARNING_OBJECT (src, "ignoring stop seek type (expected NONE)");
++  }
++
++  if (start < 0 || start >= src->num_tracks) {
++    GST_DEBUG_OBJECT (src, "invalid track %" G_GINT64_FORMAT, start);
++    return FALSE;
++  }
++
++  GST_DEBUG_OBJECT (src, "seeking to track %" G_GINT64_FORMAT, start + 1);
++
++  src->cur_sector = src->tracks[start].start;
++  GST_DEBUG_OBJECT (src, "starting at sector %d", src->cur_sector);
++
++  if (src->cur_track != start) {
++    src->cur_track = (gint) start;
++    src->uri_track = -1;
++    src->prev_track = -1;
++
++    gst_cdda_base_src_update_duration (src);
++  } else {
++    GST_DEBUG_OBJECT (src, "is current track, just seeking back to start");
++  }
++
++  /* send fake segment seek event in TIME format to
++   * base class (so we get a newsegment etc.) */
++  event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags,
++      GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
++
++  return GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
++}
++
++static gboolean
++gst_cdda_base_src_handle_event (GstBaseSrc * basesrc, GstEvent * event)
++{
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
++  gboolean ret = FALSE;
++
++  GST_LOG_OBJECT (src, "handling %s event", GST_EVENT_TYPE_NAME (event));
++
++  switch (GST_EVENT_TYPE (event)) {
++    case GST_EVENT_SEEK:{
++      GstSeekType start_type, stop_type;
++      GstSeekFlags flags;
++      GstFormat format;
++      gdouble rate;
++      gint64 start, stop;
++
++      if (!GST_OBJECT_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED)) {
++        GST_DEBUG_OBJECT (src, "seek failed: device not open");
++        break;
++      }
++
++      gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
++          &stop_type, &stop);
++
++      if (format == sector_format) {
++        GST_DEBUG_OBJECT (src, "seek in sector format not supported");
++        break;
++      }
++
++      if (format == track_format) {
++        ret = gst_cdda_base_src_handle_track_seek (src, rate, flags,
++            start_type, start, stop_type, stop);
++      } else {
++        GST_LOG_OBJECT (src, "let base class handle seek in %s format",
++            gst_format_get_name (format));
++        event = gst_event_ref (event);
++        ret = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
++      }
++      break;
++    }
++    default:{
++      GST_LOG_OBJECT (src, "let base class handle event");
++      ret = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
++      break;
++    }
++  }
++
++  return ret;
++}
++
++static GstURIType
++gst_cdda_base_src_uri_get_type (void)
++{
++  return GST_URI_SRC;
++}
++
++static gchar **
++gst_cdda_base_src_uri_get_protocols (void)
++{
++  static gchar *protocols[] = { "cdda", NULL };
++
++  return protocols;
++}
++
++static const gchar *
++gst_cdda_base_src_uri_get_uri (GstURIHandler * handler)
++{
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (handler);
++
++  GST_OBJECT_LOCK (src);
++
++  g_free (src->uri);
++
++  if (GST_OBJECT_FLAG_IS_SET (GST_BASE_SRC (src), GST_BASE_SRC_STARTED)) {
++    src->uri = g_strdup_printf ("cdda://%d", src->uri_track);
++  } else {
++    src->uri = g_strdup ("cdda://1");
++  }
++
++  GST_OBJECT_UNLOCK (src);
++
++  return src->uri;
++}
++
++/* Note: gst_element_make_from_uri() might call us with just 'cdda://' as
++ * URI and expects us to return TRUE then (and this might be in any state) */
++
++static gboolean
++gst_cdda_base_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
++{
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (handler);
++  gchar *protocol, *location;
++
++  GST_OBJECT_LOCK (src);
++
++  protocol = gst_uri_get_protocol (uri);
++  if (!protocol || strcmp (protocol, "cdda") != 0) {
++    g_free (protocol);
++    goto failed;
++  }
++  g_free (protocol);
++
++  location = gst_uri_get_location (uri);
++  if (location == NULL || *location == '\0') {
++    g_free (location);
++    location = g_strdup ("1");
++  }
++
++  src->uri_track = strtol (location, NULL, 10);
++  g_free (location);
++
++  if (src->uri_track == 0)
++    goto failed;
++
++  if (src->num_tracks > 0
++      && src->tracks != NULL && src->uri_track > src->num_tracks)
++    goto failed;
++
++  if (src->uri_track > 0 && src->tracks != NULL) {
++    GST_OBJECT_UNLOCK (src);
++
++    gst_pad_send_event (GST_BASE_SRC_PAD (src),
++        gst_event_new_seek (1.0, track_format, GST_SEEK_FLAG_FLUSH,
++            GST_SEEK_TYPE_SET, src->uri_track - 1, GST_SEEK_TYPE_NONE, -1));
++  } else {
++    /* seek will be done in start() */
++    GST_OBJECT_UNLOCK (src);
++  }
++
++  GST_LOG_OBJECT (handler, "successfully handled uri '%s'", uri);
++
++  return TRUE;
++
++failed:
++  {
++    GST_OBJECT_UNLOCK (src);
++    GST_DEBUG_OBJECT (src, "cannot handle URI '%s'", uri);
++    return FALSE;
++  }
++}
++
++static void
++gst_cdda_base_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
++{
++  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
++
++  iface->get_type = gst_cdda_base_src_uri_get_type;
++  iface->get_uri = gst_cdda_base_src_uri_get_uri;
++  iface->set_uri = gst_cdda_base_src_uri_set_uri;
++  iface->get_protocols = gst_cdda_base_src_uri_get_protocols;
++}
++
++static void
++gst_cdda_base_src_setup_interfaces (GType type)
++{
++  static const GInterfaceInfo urihandler_info = {
++    gst_cdda_base_src_uri_handler_init,
++    NULL,
++    NULL,
++  };
++
++  g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
++}
++
++/**
++ * gst_cdda_base_src_add_track:
++ * @src: a #GstCddaBaseSrc
++ * @track: address of #GstCddaBaseSrcTrack to add
++ * 
++ * CDDA sources use this function from their start vfunc to announce the
++ * available data and audio tracks to the base source class. The caller
++ * should allocate @track on the stack, the base source will do a shallow
++ * copy of the structure (and take ownership of the taglist if there is one).
++ *
++ * Returns: FALSE on error, otherwise TRUE.
++ */
++
++gboolean
++gst_cdda_base_src_add_track (GstCddaBaseSrc * src, GstCddaBaseSrcTrack * track)
++{
++  g_return_val_if_fail (GST_IS_CDDA_BASE_SRC (src), FALSE);
++  g_return_val_if_fail (track != NULL, FALSE);
++  g_return_val_if_fail (track->num > 0, FALSE);
++
++  GST_DEBUG_OBJECT (src, "adding track %2u (%2u) [%6u-%6u] [%5s], tags: %"
++      GST_PTR_FORMAT, src->num_tracks + 1, track->num, track->start,
++      track->end, (track->is_audio) ? "AUDIO" : "DATA ", track->tags);
++
++  if (src->num_tracks > 0) {
++    guint end_of_previous_track = src->tracks[src->num_tracks - 1].end;
++
++    if (track->start <= end_of_previous_track) {
++      GST_WARNING ("track %2u overlaps with previous tracks", track->num);
++      return FALSE;
++    }
++  }
++
++  GST_OBJECT_LOCK (src);
++
++  ++src->num_tracks;
++  src->tracks = g_renew (GstCddaBaseSrcTrack, src->tracks, src->num_tracks);
++  src->tracks[src->num_tracks - 1] = *track;
++
++  GST_OBJECT_UNLOCK (src);
++
++  return TRUE;
++}
++
++static void
++gst_cdda_base_src_update_duration (GstCddaBaseSrc * src)
++{
++  GstBaseSrc *basesrc;
++  GstFormat format;
++  gint64 duration;
++
++  basesrc = GST_BASE_SRC (src);
++
++  format = GST_FORMAT_TIME;
++  if (gst_pad_query_duration (GST_BASE_SRC_PAD (src), &format, &duration)) {
++    gst_segment_set_duration (&basesrc->segment, GST_FORMAT_TIME, duration);
++  } else {
++    gst_segment_set_duration (&basesrc->segment, GST_FORMAT_TIME, -1);
++    duration = GST_CLOCK_TIME_NONE;
++  }
++
++  gst_element_post_message (GST_ELEMENT (src),
++      gst_message_new_duration (GST_OBJECT (src), GST_FORMAT_TIME, -1));
++
++  GST_LOG_OBJECT (src, "duration updated to %" GST_TIME_FORMAT,
++      GST_TIME_ARGS (duration));
++}
++
++#define CD_MSF_OFFSET 150
++
++/* the cddb hash function */
++static guint
++cddb_sum (gint n)
++{
++  guint ret;
++
++  ret = 0;
++  while (n > 0) {
++    ret += (n % 10);
++    n /= 10;
++  }
++  return ret;
++}
++
++#include "sha1.h"
++
++static void
++gst_cddabasesrc_calculate_musicbrainz_discid (GstCddaBaseSrc * src)
++{
++  GString *s;
++  SHA_INFO sha;
++  guchar digest[20];
++  gchar *ptr;
++  gchar tmp[9];
++  gulong i;
++  guint leadout_sector;
++
++  s = g_string_new (NULL);
++
++  leadout_sector = src->tracks[src->num_tracks - 1].end + 1 + CD_MSF_OFFSET;
++
++  /* generate SHA digest */
++  sha_init (&sha);
++  g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[0].num);
++  g_string_append_printf (s, "%02X", src->tracks[0].num);
++  sha_update (&sha, (SHA_BYTE *) tmp, 2);
++
++  g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[src->num_tracks - 1].num);
++  g_string_append_printf (s, " %02X", src->tracks[src->num_tracks - 1].num);
++  sha_update (&sha, (SHA_BYTE *) tmp, 2);
++
++  g_snprintf (tmp, sizeof (tmp), "%08X", leadout_sector);
++  g_string_append_printf (s, " %08X", leadout_sector);
++  sha_update (&sha, (SHA_BYTE *) tmp, 8);
++
++  for (i = 0; i < 99; i++) {
++    if (i < src->num_tracks) {
++      guint frame_offset = src->tracks[i].start + CD_MSF_OFFSET;
++
++      g_snprintf (tmp, sizeof (tmp), "%08X", frame_offset);
++      g_string_append_printf (s, " %08X", frame_offset);
++      sha_update (&sha, (SHA_BYTE *) tmp, 8);
++    } else {
++      sha_update (&sha, (SHA_BYTE *) "00000000", 8);
++    }
++  }
++  sha_final (digest, &sha);
++
++  /* re-encode to base64 */
++  ptr = g_base64_encode (digest, 20);
++  i = strlen (ptr);
++
++  g_assert (i < sizeof (src->mb_discid) + 1);
++  memcpy (src->mb_discid, ptr, i);
++  src->mb_discid[i] = '\0';
++  free (ptr);
++
++  /* Replace '/', '+' and '=' by '_', '.' and '-' as specified on
++   * http://musicbrainz.org/doc/DiscIDCalculation
++   */
++  for (ptr = src->mb_discid; *ptr != '\0'; ptr++) {
++    if (*ptr == '/')
++      *ptr = '_';
++    else if (*ptr == '+')
++      *ptr = '.';
++    else if (*ptr == '=')
++      *ptr = '-';
++  }
++
++  GST_DEBUG_OBJECT (src, "musicbrainz-discid      = %s", src->mb_discid);
++  GST_DEBUG_OBJECT (src, "musicbrainz-discid-full = %s", s->str);
++
++  gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
++      GST_TAG_CDDA_MUSICBRAINZ_DISCID, src->mb_discid,
++      GST_TAG_CDDA_MUSICBRAINZ_DISCID_FULL, s->str, NULL);
++
++  g_string_free (s, TRUE);
++}
++
++static void
++lba_to_msf (guint sector, guint * p_m, guint * p_s, guint * p_f, guint * p_secs)
++{
++  guint m, s, f;
++
++  m = sector / SECTORS_PER_MINUTE;
++  sector = sector % SECTORS_PER_MINUTE;
++  s = sector / SECTORS_PER_SECOND;
++  f = sector % SECTORS_PER_SECOND;
++
++  if (p_m)
++    *p_m = m;
++  if (p_s)
++    *p_s = s;
++  if (p_f)
++    *p_f = f;
++  if (p_secs)
++    *p_secs = s + (m * 60);
++}
++
++static void
++gst_cdda_base_src_calculate_cddb_id (GstCddaBaseSrc * src)
++{
++  GString *s;
++  guint first_sector = 0, last_sector = 0;
++  guint start_secs, end_secs, secs, len_secs;
++  guint total_secs, num_audio_tracks;
++  guint id, t, i;
++
++  id = 0;
++  total_secs = 0;
++  num_audio_tracks = 0;
++
++  /* FIXME: do we use offsets and duration of ALL tracks (data + audio)
++   * for the CDDB ID calculation, or only audio tracks? */
++  for (i = 0; i < src->num_tracks; ++i) {
++    if (1) {                    /* src->tracks[i].is_audio) { */
++      if (num_audio_tracks == 0) {
++        first_sector = src->tracks[i].start + CD_MSF_OFFSET;
++      }
++      last_sector = src->tracks[i].end + CD_MSF_OFFSET + 1;
++      ++num_audio_tracks;
++
++      lba_to_msf (src->tracks[i].start + CD_MSF_OFFSET, NULL, NULL, NULL,
++          &secs);
++
++      len_secs = (src->tracks[i].end - src->tracks[i].start + 1) / 75;
++
++      GST_DEBUG_OBJECT (src, "track %02u: lsn %6u (%02u:%02u), "
++          "length: %u seconds (%02u:%02u)",
++          num_audio_tracks, src->tracks[i].start + CD_MSF_OFFSET,
++          secs / 60, secs % 60, len_secs, len_secs / 60, len_secs % 60);
++
++      id += cddb_sum (secs);
++      total_secs += len_secs;
++    }
++  }
++
++  /* first_sector = src->tracks[0].start + CD_MSF_OFFSET; */
++  lba_to_msf (first_sector, NULL, NULL, NULL, &start_secs);
++
++  /* last_sector = src->tracks[src->num_tracks-1].end + CD_MSF_OFFSET; */
++  lba_to_msf (last_sector, NULL, NULL, NULL, &end_secs);
++
++  GST_DEBUG_OBJECT (src, "first_sector = %u = %u secs (%02u:%02u)",
++      first_sector, start_secs, start_secs / 60, start_secs % 60);
++  GST_DEBUG_OBJECT (src, "last_sector  = %u = %u secs (%02u:%02u)",
++      last_sector, end_secs, end_secs / 60, end_secs % 60);
++
++  t = end_secs - start_secs;
++
++  GST_DEBUG_OBJECT (src, "total length = %u secs (%02u:%02u), added title "
++      "lengths = %u seconds (%02u:%02u)", t, t / 60, t % 60, total_secs,
++      total_secs / 60, total_secs % 60);
++
++  src->discid = ((id % 0xff) << 24 | t << 8 | num_audio_tracks);
++
++  s = g_string_new (NULL);
++  g_string_append_printf (s, "%08x", src->discid);
++
++  gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
++      GST_TAG_CDDA_CDDB_DISCID, s->str, NULL);
++
++  g_string_append_printf (s, " %u", src->num_tracks);
++  for (i = 0; i < src->num_tracks; ++i) {
++    g_string_append_printf (s, " %u", src->tracks[i].start + CD_MSF_OFFSET);
++  }
++  g_string_append_printf (s, " %u", t);
++
++  gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
++      GST_TAG_CDDA_CDDB_DISCID_FULL, s->str, NULL);
++
++  GST_DEBUG_OBJECT (src, "cddb discid = %s", s->str);
++
++  g_string_free (s, TRUE);
++}
++
++static void
++gst_cdda_base_src_add_tags (GstCddaBaseSrc * src)
++{
++  gint i;
++
++  /* fill in details for each track */
++  for (i = 0; i < src->num_tracks; ++i) {
++    gint64 duration;
++    guint num_sectors;
++
++    if (src->tracks[i].tags == NULL)
++      src->tracks[i].tags = gst_tag_list_new ();
++
++    num_sectors = src->tracks[i].end - src->tracks[i].start + 1;
++    gst_cdda_base_src_convert (src, sector_format, num_sectors,
++        GST_FORMAT_TIME, &duration);
++
++    gst_tag_list_add (src->tracks[i].tags,
++        GST_TAG_MERGE_REPLACE,
++        GST_TAG_TRACK_NUMBER, i + 1,
++        GST_TAG_TRACK_COUNT, src->num_tracks, GST_TAG_DURATION, duration, NULL);
++  }
++
++  /* now fill in per-album tags and include each track's tags
++   * in the album tags, so that interested parties can retrieve
++   * the relevant details for each track in one go */
++
++  /* /////////////////////////////// FIXME should we rather insert num_tracks
++   * tags by the name of 'track-tags' and have the caller use
++   * gst_tag_list_get_value_index() rather than use tag names incl.
++   * the track number ?? *////////////////////////////////////////
++
++  gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
++      GST_TAG_TRACK_COUNT, src->num_tracks, NULL);
++#if 0
++  for (i = 0; i < src->num_tracks; ++i) {
++    gst_tag_list_add (src->tags, GST_TAG_MERGE_APPEND,
++        GST_TAG_CDDA_TRACK_TAGS, src->tracks[i].tags, NULL);
++  }
++#endif
++
++  GST_DEBUG ("src->tags = %" GST_PTR_FORMAT, src->tags);
++}
++
++static void
++gst_cdda_base_src_add_index_associations (GstCddaBaseSrc * src)
++{
++  gint i;
++
++  for (i = 0; i < src->num_tracks; i++) {
++    gint64 sector;
++
++    sector = src->tracks[i].start;
++    gst_index_add_association (src->index, src->index_id, GST_ASSOCIATION_FLAG_KEY_UNIT, track_format, i,       /* here we count from 0 */
++        sector_format, sector,
++        GST_FORMAT_TIME,
++        (gint64) (((CD_FRAMESIZE_RAW >> 2) * sector * GST_SECOND) / 44100),
++        GST_FORMAT_BYTES, (gint64) (sector << 2), GST_FORMAT_DEFAULT,
++        (gint64) ((CD_FRAMESIZE_RAW >> 2) * sector), NULL);
++  }
++}
++
++static void
++gst_cdda_base_src_set_index (GstElement * element, GstIndex * index)
++{
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (element);
++
++  src->index = index;
++
++  gst_index_get_writer_id (index, GST_OBJECT (src), &src->index_id);
++  gst_index_add_format (index, src->index_id, track_format);
++  gst_index_add_format (index, src->index_id, sector_format);
++}
++
++
++static GstIndex *
++gst_cdda_base_src_get_index (GstElement * element)
++{
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (element);
++
++  return src->index;
++}
++
++static gint
++gst_cdda_base_src_track_sort_func (gconstpointer a, gconstpointer b,
++    gpointer foo)
++{
++  GstCddaBaseSrcTrack *track_a = ((GstCddaBaseSrcTrack *) a);
++  GstCddaBaseSrcTrack *track_b = ((GstCddaBaseSrcTrack *) b);
++
++  /* sort data tracks to the end, and audio tracks by track number */
++  if (track_a->is_audio == track_b->is_audio)
++    return (gint) track_a->num - (gint) track_b->num;
++
++  if (track_a->is_audio) {
++    return -1;
++  } else {
++    return 1;
++  }
++}
++
++static gboolean
++gst_cdda_base_src_start (GstBaseSrc * basesrc)
++{
++  GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (basesrc);
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
++  gboolean ret;
++  gchar *device = NULL;
++
++  src->discid = 0;
++  src->mb_discid[0] = '\0';
++
++  g_assert (klass->open != NULL);
++
++  if (src->device != NULL) {
++    device = g_strdup (src->device);
++  } else if (klass->get_default_device != NULL) {
++    device = klass->get_default_device (src);
++  }
++
++  if (device == NULL)
++    device = g_strdup (DEFAULT_DEVICE);
++
++  GST_LOG_OBJECT (basesrc, "opening device %s", device);
++
++  src->tags = gst_tag_list_new ();
++
++  ret = klass->open (src, device);
++  g_free (device);
++  device = NULL;
++
++  if (!ret) {
++    GST_DEBUG_OBJECT (basesrc, "failed to open device");
++    /* subclass (should have) posted an error message with the details */
++    gst_cdda_base_src_stop (basesrc);
++    return FALSE;
++  }
++
++  if (src->num_tracks == 0 || src->tracks == NULL) {
++    GST_DEBUG_OBJECT (src, "no tracks");
++    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
++        (_("This CD has no audio tracks")), (NULL));
++    gst_cdda_base_src_stop (basesrc);
++    return FALSE;
++  }
++
++  /* need to calculate disc IDs before we ditch the data tracks */
++  gst_cdda_base_src_calculate_cddb_id (src);
++  gst_cddabasesrc_calculate_musicbrainz_discid (src);
++
++#if 0
++  /* adjust sector offsets if necessary */
++  if (src->toc_bias) {
++    src->toc_offset -= src->tracks[0].start;
++  }
++  for (i = 0; i < src->num_tracks; ++i) {
++    src->tracks[i].start += src->toc_offset;
++    src->tracks[i].end += src->toc_offset;
++  }
++#endif
++
++  /* now that we calculated the various disc IDs,
++   * sort the data tracks to end and ignore them */
++  src->num_all_tracks = src->num_tracks;
++
++  g_qsort_with_data (src->tracks, src->num_tracks,
++      sizeof (GstCddaBaseSrcTrack), gst_cdda_base_src_track_sort_func, NULL);
++
++  while (src->num_tracks > 0 && !src->tracks[src->num_tracks - 1].is_audio)
++    --src->num_tracks;
++
++  if (src->num_tracks == 0) {
++    GST_DEBUG_OBJECT (src, "no audio tracks");
++    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
++        (_("This CD has no audio tracks")), (NULL));
++    gst_cdda_base_src_stop (basesrc);
++    return FALSE;
++  }
++
++  gst_cdda_base_src_add_tags (src);
++
++  if (src->index && GST_INDEX_IS_WRITABLE (src->index))
++    gst_cdda_base_src_add_index_associations (src);
++
++  src->cur_track = 0;
++  src->prev_track = -1;
++
++  if (src->uri_track > 0 && src->uri_track <= src->num_tracks) {
++    GST_LOG_OBJECT (src, "seek to track %d", src->uri_track);
++    src->cur_track = src->uri_track - 1;
++    src->uri_track = -1;
++    src->mode = GST_CDDA_BASE_SRC_MODE_NORMAL;
++  }
++
++  src->cur_sector = src->tracks[src->cur_track].start;
++  GST_LOG_OBJECT (src, "starting at sector %d", src->cur_sector);
++
++  gst_cdda_base_src_update_duration (src);
++
++  return TRUE;
++}
++
++static void
++gst_cdda_base_src_clear_tracks (GstCddaBaseSrc * src)
++{
++  if (src->tracks != NULL) {
++    gint i;
++
++    for (i = 0; i < src->num_all_tracks; ++i) {
++      if (src->tracks[i].tags)
++        gst_tag_list_free (src->tracks[i].tags);
++    }
++
++    g_free (src->tracks);
++    src->tracks = NULL;
++  }
++  src->num_tracks = 0;
++  src->num_all_tracks = 0;
++}
++
++static gboolean
++gst_cdda_base_src_stop (GstBaseSrc * basesrc)
++{
++  GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (basesrc);
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
++
++  g_assert (klass->close != NULL);
++
++  klass->close (src);
++
++  gst_cdda_base_src_clear_tracks (src);
++
++  if (src->tags) {
++    gst_tag_list_free (src->tags);
++    src->tags = NULL;
++  }
++
++  src->prev_track = -1;
++  src->cur_track = -1;
++
++  return TRUE;
++}
++
++
++static GstFlowReturn
++gst_cdda_base_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
++{
++  GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (pushsrc);
++  GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (pushsrc);
++  GstBuffer *buf;
++  GstFormat format;
++  gboolean eos;
++
++  GstClockTime position = GST_CLOCK_TIME_NONE;
++  GstClockTime duration = GST_CLOCK_TIME_NONE;
++  gint64 qry_position;
++
++  g_assert (klass->read_sector != NULL);
++
++  switch (src->mode) {
++    case GST_CDDA_BASE_SRC_MODE_NORMAL:
++      eos = (src->cur_sector > src->tracks[src->cur_track].end);
++      break;
++    case GST_CDDA_BASE_SRC_MODE_CONTINUOUS:
++      eos = (src->cur_sector > src->tracks[src->num_tracks - 1].end);
++      src->cur_track = gst_cdda_base_src_get_track_from_sector (src,
++          src->cur_sector);
++      break;
++    default:
++      g_return_val_if_reached (GST_FLOW_ERROR);
++  }
++
++  if (eos) {
++    src->prev_track = -1;
++    GST_DEBUG_OBJECT (src, "EOS at sector %d, cur_track=%d, mode=%d",
++        src->cur_sector, src->cur_track, src->mode);
++    /* base class will send EOS for us */
++    return GST_FLOW_UNEXPECTED;
++  }
++
++  if (src->prev_track != src->cur_track) {
++    GstTagList *tags;
++
++    tags = gst_tag_list_merge (src->tags, src->tracks[src->cur_track].tags,
++        GST_TAG_MERGE_REPLACE);
++    GST_LOG_OBJECT (src, "announcing tags: %" GST_PTR_FORMAT, tags);
++    gst_element_found_tags_for_pad (GST_ELEMENT (src),
++        GST_BASE_SRC_PAD (src), tags);
++    src->prev_track = src->cur_track;
++
++    gst_cdda_base_src_update_duration (src);
++
++    g_object_notify (G_OBJECT (src), "track");
++  }
++
++  GST_LOG_OBJECT (src, "asking for sector %u", src->cur_sector);
++
++  buf = klass->read_sector (src, src->cur_sector);
++
++  if (buf == NULL) {
++    GST_WARNING_OBJECT (src, "failed to read sector %u", src->cur_sector);
++    return GST_FLOW_ERROR;
++  }
++
++  if (GST_BUFFER_CAPS (buf) == NULL) {
++    gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
++  }
++
++  format = GST_FORMAT_TIME;
++  if (gst_pad_query_position (GST_BASE_SRC_PAD (src), &format, &qry_position)) {
++    gint64 next_ts = 0;
++
++    position = (GstClockTime) qry_position;
++
++    ++src->cur_sector;
++    if (gst_pad_query_position (GST_BASE_SRC_PAD (src), &format, &next_ts)) {
++      duration = (GstClockTime) (next_ts - qry_position);
++    }
++    --src->cur_sector;
++  }
++
++  /* fallback duration: 4 bytes per sample, 44100 samples per second */
++  if (duration == GST_CLOCK_TIME_NONE) {
++    duration = gst_util_uint64_scale_int (GST_BUFFER_SIZE (buf) >> 2,
++        GST_SECOND, 44100);
++  }
++
++  GST_BUFFER_TIMESTAMP (buf) = position;
++  GST_BUFFER_DURATION (buf) = duration;
++
++  GST_LOG_OBJECT (src, "pushing sector %d with timestamp %" GST_TIME_FORMAT,
++      src->cur_sector, GST_TIME_ARGS (position));
++
++  ++src->cur_sector;
++
++  *buffer = buf;
++
++  return GST_FLOW_OK;
++}
index 0000000,0000000..ad50816
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,224 @@@
++diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.c b/gst-libs/gst/rtp/gstrtcpbuffer.c
++index ab77c8a..fb35a92 100644
++--- a/gst-libs/gst/rtp/gstrtcpbuffer.c
+++++ b/gst-libs/gst/rtp/gstrtcpbuffer.c
++@@ -449,6 +449,11 @@ gst_rtcp_buffer_add_packet (GstBuffer * buffer, GstRTCPType type,
++     case GST_RTCP_TYPE_APP:
++       len = 12;
++       break;
+++    case GST_RTCP_TYPE_RTPFB:
+++      len = 12;
+++      break;
+++    case GST_RTCP_TYPE_PSFB:
+++      len = 12;
++     default:
++       goto unknown_type;
++   }
++@@ -1637,6 +1642,147 @@ no_space:
++ }
++ 
++ /**
+++ * gst_rtcp_packet_fb_get_sender_ssrc:
+++ * @packet: a valid RTPFB or PSFB #GstRTCPPacket
+++ *
+++ * Get the sender SSRC field of the RTPFB or PSFB @packet.
+++ *
+++ * Returns: the sender SSRC.
+++ */
+++guint32
+++gst_rtcp_packet_fb_get_sender_ssrc (GstRTCPPacket * packet)
+++{
+++  guint8 *data;
+++  guint32 ssrc;
+++
+++  g_return_val_if_fail (packet != NULL, 0);
+++  g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
+++      packet->type == GST_RTCP_TYPE_PSFB), 0);
+++  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+++
+++  data = GST_BUFFER_DATA (packet->buffer);
+++
+++  /* skip header */
+++  data += packet->offset + 4;
+++  ssrc = GST_READ_UINT32_BE (data);
+++
+++  return ssrc;
+++}
+++
+++/**
+++ * gst_rtcp_packet_fb_set_sender_ssrc:
+++ * @packet: a valid RTPFB or PSFB #GstRTCPPacket
+++ *
+++ * Set the sender SSRC field of the RTPFB or PSFB @packet.
+++ */
+++void
+++gst_rtcp_packet_fb_set_sender_ssrc (GstRTCPPacket *packet, guint32 ssrc)
+++{
+++  guint8 *data;
+++
+++  g_return_if_fail (packet != NULL);
+++  g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
+++      packet->type == GST_RTCP_TYPE_PSFB);
+++  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+++
+++  data = GST_BUFFER_DATA (packet->buffer);
+++
+++  /* skip header */
+++  data += packet->offset + 4;
+++  GST_WRITE_UINT32_BE (data, ssrc);
+++}
+++
+++/**
+++ * gst_rtcp_packet_fb_get_media_ssrc:
+++ * @packet: a valid RTPFB or PSFB #GstRTCPPacket
+++ *
+++ * Get the media SSRC field of the RTPFB or PSFB @packet.
+++ *
+++ * Returns: the media SSRC.
+++ */
+++guint32
+++gst_rtcp_packet_fb_get_media_ssrc (GstRTCPPacket * packet)
+++{
+++  guint8 *data;
+++  guint32 ssrc;
+++
+++  g_return_val_if_fail (packet != NULL, 0);
+++  g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
+++      packet->type == GST_RTCP_TYPE_PSFB), 0);
+++  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+++
+++  data = GST_BUFFER_DATA (packet->buffer);
+++
+++  /* skip header and sender ssrc */
+++  data += packet->offset + 8;
+++  ssrc = GST_READ_UINT32_BE (data);
+++
+++  return ssrc;
+++}
+++
+++/**
+++ * gst_rtcp_packet_fb_set_media_ssrc:
+++ * @packet: a valid RTPFB or PSFB #GstRTCPPacket
+++ *
+++ * Set the media SSRC field of the RTPFB or PSFB @packet.
+++ */
+++void
+++gst_rtcp_packet_fb_set_media_ssrc (GstRTCPPacket *packet, guint32 ssrc)
+++{
+++  guint8 *data;
+++
+++  g_return_if_fail (packet != NULL);
+++  g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
+++      packet->type == GST_RTCP_TYPE_PSFB);
+++  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+++
+++  data = GST_BUFFER_DATA (packet->buffer);
+++
+++  /* skip header and sender ssrc */
+++  data += packet->offset + 8;
+++  GST_WRITE_UINT32_BE (data, ssrc);
+++}
+++
+++/**
+++ * gst_rtcp_packet_psfb_get_type:
+++ * @packet: a valid PSFB #GstRTCPPacket
+++ *
+++ * Get the feedback message type of the PSFB @packet.
+++ *
+++ * Returns: The feedback message type.
+++ */
+++GstRTCPPSFBType
+++gst_rtcp_packet_psfb_get_type (GstRTCPPacket *packet)
+++{
+++  g_return_val_if_fail (packet != NULL, GST_RTCP_PSFB_TYPE_INVALID);
+++  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_PSFB,
+++      GST_RTCP_PSFB_TYPE_INVALID);
+++
+++  return packet->count;
+++}
+++
+++/**
+++ * gst_rtcp_packet_psfb_set_type:
+++ * @packet: a valid PSFB #GstRTCPPacket
+++ * @type: the #GstRTCPPSFBType to set
+++ *
+++ * Set the feedback message type of the PSFB @packet.
+++ */
+++void
+++gst_rtcp_packet_psfb_set_type (GstRTCPPacket *packet, GstRTCPPSFBType type)
+++{
+++  guint8 *data;
+++
+++  g_return_if_fail (packet != NULL);
+++  g_return_if_fail (packet->type == GST_RTCP_TYPE_PSFB);
+++  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+++
+++  data = GST_BUFFER_DATA (packet->buffer);
+++
+++  data[packet->offset] = (data[packet->offset] & 0xE0) | type;
+++}
+++
+++/**
++  * gst_rtcp_ntp_to_unix:
++  * @ntptime: an NTP timestamp
++  *
++diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.h b/gst-libs/gst/rtp/gstrtcpbuffer.h
++index 9c908a8..bb247c9 100644
++--- a/gst-libs/gst/rtp/gstrtcpbuffer.h
+++++ b/gst-libs/gst/rtp/gstrtcpbuffer.h
++@@ -42,6 +42,8 @@ G_BEGIN_DECLS
++  * @GST_RTCP_TYPE_SDES: Source description
++  * @GST_RTCP_TYPE_BYE: Goodbye
++  * @GST_RTCP_TYPE_APP: Application defined
+++ * @GST_RTCP_TYPE_RTPFB: Transport layer feedback
+++ * @GST_RTCP_TYPE_PSFB: Payload-specific feedback
++  *
++  * Different RTCP packet types.
++  */
++@@ -52,9 +54,28 @@ typedef enum
++   GST_RTCP_TYPE_RR      = 201,
++   GST_RTCP_TYPE_SDES    = 202,
++   GST_RTCP_TYPE_BYE     = 203,
++-  GST_RTCP_TYPE_APP     = 204
+++  GST_RTCP_TYPE_APP     = 204,
+++  GST_RTCP_TYPE_RTPFB   = 205,
+++  GST_RTCP_TYPE_PSFB    = 206
++ } GstRTCPType;
++ 
+++/**
+++ * GstRTCPPSFBType:
+++ * @GST_RTCP_PSFB_TYPE_INVALID: Invalid type
+++ * @GST_RTCP_PSFB_TYPE_PLI: Picture Loss Indication
+++ * @GST_RTCP_PSFB_TYPE_SLI: Slice Loss Indication
+++ * @GST_RTCP_PSFB_TYPE_RPSI: Reference Picture Selection Indication
+++ * @GST_RTCP_PSFB_TYPE_AFB: Application layer Feedback
+++ */
+++typedef enum
+++{
+++  GST_RTCP_PSFB_TYPE_INVALID = 0,
+++  GST_RTCP_PSFB_TYPE_PLI     = 1,
+++  GST_RTCP_PSFB_TYPE_SLI     = 2,
+++  GST_RTCP_PSFB_TYPE_RPSI    = 3,
+++  GST_RTCP_PSFB_TYPE_AFB     = 15
+++} GstRTCPPSFBType;
+++
++ /** 
++  * GstRTCPSDESType:
++  * @GST_RTCP_SDES_INVALID: Invalid SDES entry
++@@ -232,6 +253,16 @@ guint8          gst_rtcp_packet_bye_get_reason_len    (GstRTCPPacket *packet);
++ gchar*          gst_rtcp_packet_bye_get_reason        (GstRTCPPacket *packet);
++ gboolean        gst_rtcp_packet_bye_set_reason        (GstRTCPPacket *packet, const gchar *reason);
++ 
+++/* feedback packets */
+++guint32         gst_rtcp_packet_fb_get_sender_ssrc    (GstRTCPPacket *packet);
+++void            gst_rtcp_packet_fb_set_sender_ssrc    (GstRTCPPacket *packet, guint32 ssrc);
+++guint32         gst_rtcp_packet_fb_get_media_ssrc     (GstRTCPPacket *packet);
+++void            gst_rtcp_packet_fb_set_media_ssrc     (GstRTCPPacket *packet, guint32 ssrc);
+++
+++/* psfb packets */
+++GstRTCPPSFBType gst_rtcp_packet_psfb_get_type         (GstRTCPPacket *packet);
+++void            gst_rtcp_packet_psfb_set_type         (GstRTCPPacket *packet, GstRTCPPSFBType type);
+++
++ /* helper functions */
++ guint64         gst_rtcp_ntp_to_unix                  (guint64 ntptime);
++ guint64         gst_rtcp_unix_to_ntp                  (guint64 unixtime);
index 0000000,0000000..e1cc721
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1040 @@@
++/* GStreamer
++ * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more
++ */
++
++/**
++ * SECTION:gstbasertppayload
++ * @short_description: Base class for RTP payloader
++ *
++ * <refsect2>
++ * <para>
++ * Provides a base class for RTP payloaders
++ * </para>
++ * </refsect2>
++ */
++
++#ifdef HAVE_CONFIG_H
++#  include "config.h"
++#endif
++
++#include <string.h>
++
++#include <gst/rtp/gstrtpbuffer.h>
++
++#include "gstbasertppayload.h"
++
++GST_DEBUG_CATEGORY_STATIC (basertppayload_debug);
++#define GST_CAT_DEFAULT (basertppayload_debug)
++
++#define GST_BASE_RTP_PAYLOAD_GET_PRIVATE(obj)  \
++   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_RTP_PAYLOAD, GstBaseRTPPayloadPrivate))
++
++struct _GstBaseRTPPayloadPrivate
++{
++  gboolean ts_offset_random;
++  gboolean seqnum_offset_random;
++  gboolean ssrc_random;
++  guint16 next_seqnum;
++  gboolean perfect_rtptime;
++
++  gint64 prop_max_ptime;
++  gint64 caps_max_ptime;
++};
++
++/* BaseRTPPayload signals and args */
++enum
++{
++  /* FILL ME */
++  LAST_SIGNAL
++};
++
++/* FIXME 0.11, a better default is the Ethernet MTU of
++ * 1500 - sizeof(headers) as pointed out by marcelm in IRC:
++ * So an Ethernet MTU of 1500, minus 60 for the max IP, minus 8 for UDP, gives
++ * 1432 bytes or so.  And that should be adjusted downward further for other
++ * encapsulations like PPPoE, so 1400 at most.
++ */
++#define DEFAULT_MTU                     1400
++#define DEFAULT_PT                      96
++#define DEFAULT_SSRC                    -1
++#define DEFAULT_TIMESTAMP_OFFSET        -1
++#define DEFAULT_SEQNUM_OFFSET           -1
++#define DEFAULT_MAX_PTIME               -1
++#define DEFAULT_MIN_PTIME               0
++#define DEFAULT_PERFECT_RTPTIME         TRUE
++#define DEFAULT_PTIME_MULTIPLE          0
++
++enum
++{
++  PROP_0,
++  PROP_MTU,
++  PROP_PT,
++  PROP_SSRC,
++  PROP_TIMESTAMP_OFFSET,
++  PROP_SEQNUM_OFFSET,
++  PROP_MAX_PTIME,
++  PROP_MIN_PTIME,
++  PROP_TIMESTAMP,
++  PROP_SEQNUM,
++  PROP_PERFECT_RTPTIME,
++  PROP_PTIME_MULTIPLE,
++  PROP_LAST
++};
++
++static void gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass);
++static void gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass);
++static void gst_basertppayload_init (GstBaseRTPPayload * basertppayload,
++    gpointer g_class);
++static void gst_basertppayload_finalize (GObject * object);
++
++static gboolean gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps);
++static GstCaps *gst_basertppayload_sink_getcaps (GstPad * pad);
++static gboolean gst_basertppayload_event (GstPad * pad, GstEvent * event);
++static GstFlowReturn gst_basertppayload_chain (GstPad * pad,
++    GstBuffer * buffer);
++
++static void gst_basertppayload_set_property (GObject * object, guint prop_id,
++    const GValue * value, GParamSpec * pspec);
++static void gst_basertppayload_get_property (GObject * object, guint prop_id,
++    GValue * value, GParamSpec * pspec);
++
++static GstStateChangeReturn gst_basertppayload_change_state (GstElement *
++    element, GstStateChange transition);
++
++static GstElementClass *parent_class = NULL;
++
++/* FIXME 0.11: API should be changed to gst_base_typ_payload_xyz */
++
++GType
++gst_basertppayload_get_type (void)
++{
++  static GType basertppayload_type = 0;
++
++  if (!basertppayload_type) {
++    static const GTypeInfo basertppayload_info = {
++      sizeof (GstBaseRTPPayloadClass),
++      (GBaseInitFunc) gst_basertppayload_base_init,
++      NULL,
++      (GClassInitFunc) gst_basertppayload_class_init,
++      NULL,
++      NULL,
++      sizeof (GstBaseRTPPayload),
++      0,
++      (GInstanceInitFunc) gst_basertppayload_init,
++    };
++
++    basertppayload_type =
++        g_type_register_static (GST_TYPE_ELEMENT, "GstBaseRTPPayload",
++        &basertppayload_info, G_TYPE_FLAG_ABSTRACT);
++  }
++  return basertppayload_type;
++}
++
++static void
++gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass)
++{
++}
++
++static void
++gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass)
++{
++  GObjectClass *gobject_class;
++  GstElementClass *gstelement_class;
++
++  gobject_class = (GObjectClass *) klass;
++  gstelement_class = (GstElementClass *) klass;
++
++  g_type_class_add_private (klass, sizeof (GstBaseRTPPayloadPrivate));
++
++  parent_class = g_type_class_peek_parent (klass);
++
++  gobject_class->finalize = gst_basertppayload_finalize;
++
++  gobject_class->set_property = gst_basertppayload_set_property;
++  gobject_class->get_property = gst_basertppayload_get_property;
++
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
++      g_param_spec_uint ("mtu", "MTU",
++          "Maximum size of one packet",
++          28, G_MAXUINT, DEFAULT_MTU,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
++      g_param_spec_uint ("pt", "payload type",
++          "The payload type of the packets", 0, 0x80, DEFAULT_PT,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
++      g_param_spec_uint ("ssrc", "SSRC",
++          "The SSRC of the packets (default == random)", 0, G_MAXUINT32,
++          DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++  g_object_class_install_property (G_OBJECT_CLASS (klass),
++      PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset",
++          "Timestamp Offset",
++          "Offset to add to all outgoing timestamps (default = random)", 0,
++          G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
++      g_param_spec_int ("seqnum-offset", "Sequence number Offset",
++          "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16,
++          DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PTIME,
++      g_param_spec_int64 ("max-ptime", "Max packet time",
++          "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)",
++          -1, G_MAXINT64, DEFAULT_MAX_PTIME,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++  /**
++   * GstBaseRTPAudioPayload:min-ptime:
++   *
++   * Minimum duration of the packet data in ns (can't go above MTU)
++   *
++   * Since: 0.10.13
++   **/
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME,
++      g_param_spec_int64 ("min-ptime", "Min packet time",
++          "Minimum duration of the packet data in ns (can't go above MTU)",
++          0, G_MAXINT64, DEFAULT_MIN_PTIME,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP,
++      g_param_spec_uint ("timestamp", "Timestamp",
++          "The RTP timestamp of the last processed packet",
++          0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
++      g_param_spec_uint ("seqnum", "Sequence number",
++          "The RTP sequence number of the last processed packet",
++          0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
++
++  /**
++   * GstBaseRTPAudioPayload:perfect-rtptime:
++   *
++   * Try to use the offset fields to generate perfect RTP timestamps. when this
++   * option is disabled, RTP timestamps are generated from the GStreamer
++   * timestamps, which could result in RTP timestamps that don't increment with
++   * the amount of data in the packet.
++   *
++   * Since: 0.10.25
++   */
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PERFECT_RTPTIME,
++      g_param_spec_boolean ("perfect-rtptime", "Perfect RTP Time",
++          "Generate perfect RTP timestamps when possible",
++          DEFAULT_PERFECT_RTPTIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++  /**
++   * GstBaseRTPAudioPayload:ptime-multiple:
++   *
++   * Force buffers to be multiples of this duration in ns (0 disables)
++   *
++   * Since: 0.10.29
++   **/
++  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PTIME_MULTIPLE,
++      g_param_spec_int64 ("ptime-multiple", "Packet time multiple",
++          "Force buffers to be multiples of this duration in ns (0 disables)",
++          0, G_MAXINT64, DEFAULT_PTIME_MULTIPLE,
++          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++
++  gstelement_class->change_state = gst_basertppayload_change_state;
++
++  GST_DEBUG_CATEGORY_INIT (basertppayload_debug, "basertppayload", 0,
++      "Base class for RTP Payloaders");
++}
++
++static void
++gst_basertppayload_init (GstBaseRTPPayload * basertppayload, gpointer g_class)
++{
++  GstPadTemplate *templ;
++  GstBaseRTPPayloadPrivate *priv;
++
++  basertppayload->priv = priv =
++      GST_BASE_RTP_PAYLOAD_GET_PRIVATE (basertppayload);
++
++  templ =
++      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
++  g_return_if_fail (templ != NULL);
++
++  basertppayload->srcpad = gst_pad_new_from_template (templ, "src");
++  gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->srcpad);
++
++  templ =
++      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
++  g_return_if_fail (templ != NULL);
++
++  basertppayload->sinkpad = gst_pad_new_from_template (templ, "sink");
++  gst_pad_set_setcaps_function (basertppayload->sinkpad,
++      gst_basertppayload_sink_setcaps);
++  gst_pad_set_getcaps_function (basertppayload->sinkpad,
++      gst_basertppayload_sink_getcaps);
++  gst_pad_set_event_function (basertppayload->sinkpad,
++      gst_basertppayload_event);
++  gst_pad_set_chain_function (basertppayload->sinkpad,
++      gst_basertppayload_chain);
++  gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->sinkpad);
++
++  basertppayload->seq_rand = g_rand_new_with_seed (g_random_int ());
++  basertppayload->ssrc_rand = g_rand_new_with_seed (g_random_int ());
++  basertppayload->ts_rand = g_rand_new_with_seed (g_random_int ());
++
++  basertppayload->mtu = DEFAULT_MTU;
++  basertppayload->pt = DEFAULT_PT;
++  basertppayload->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
++  basertppayload->ssrc = DEFAULT_SSRC;
++  basertppayload->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
++  priv->seqnum_offset_random = (basertppayload->seqnum_offset == -1);
++  priv->ts_offset_random = (basertppayload->ts_offset == -1);
++  priv->ssrc_random = (basertppayload->ssrc == -1);
++
++  basertppayload->max_ptime = DEFAULT_MAX_PTIME;
++  basertppayload->min_ptime = DEFAULT_MIN_PTIME;
++  basertppayload->priv->perfect_rtptime = DEFAULT_PERFECT_RTPTIME;
++  basertppayload->abidata.ABI.ptime_multiple = DEFAULT_PTIME_MULTIPLE;
++
++  basertppayload->media = NULL;
++  basertppayload->encoding_name = NULL;
++
++  basertppayload->clock_rate = 0;
++
++  basertppayload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
++  basertppayload->priv->prop_max_ptime = DEFAULT_MAX_PTIME;
++}
++
++static void
++gst_basertppayload_finalize (GObject * object)
++{
++  GstBaseRTPPayload *basertppayload;
++
++  basertppayload = GST_BASE_RTP_PAYLOAD (object);
++
++  g_rand_free (basertppayload->seq_rand);
++  basertppayload->seq_rand = NULL;
++  g_rand_free (basertppayload->ssrc_rand);
++  basertppayload->ssrc_rand = NULL;
++  g_rand_free (basertppayload->ts_rand);
++  basertppayload->ts_rand = NULL;
++
++  g_free (basertppayload->media);
++  basertppayload->media = NULL;
++  g_free (basertppayload->encoding_name);
++  basertppayload->encoding_name = NULL;
++
++  G_OBJECT_CLASS (parent_class)->finalize (object);
++}
++
++static gboolean
++gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps)
++{
++  GstBaseRTPPayload *basertppayload;
++  GstBaseRTPPayloadClass *basertppayload_class;
++  gboolean ret = TRUE;
++
++  GST_DEBUG_OBJECT (pad, "setting caps %" GST_PTR_FORMAT, caps);
++  basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad));
++  basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);
++
++  if (basertppayload_class->set_caps)
++    ret = basertppayload_class->set_caps (basertppayload, caps);
++
++  gst_object_unref (basertppayload);
++
++  return ret;
++}
++
++static GstCaps *
++gst_basertppayload_sink_getcaps (GstPad * pad)
++{
++  GstBaseRTPPayload *basertppayload;
++  GstBaseRTPPayloadClass *basertppayload_class;
++  GstCaps *caps = NULL;
++
++  GST_DEBUG_OBJECT (pad, "getting caps");
++
++  basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad));
++  basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);
++
++  if (basertppayload_class->get_caps)
++    caps = basertppayload_class->get_caps (basertppayload, pad);
++
++  if (!caps) {
++    caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad));
++    GST_DEBUG_OBJECT (pad,
++        "using pad template %p with caps %p %" GST_PTR_FORMAT,
++        GST_PAD_PAD_TEMPLATE (pad), caps, caps);
++
++    caps = gst_caps_ref (caps);
++  }
++
++  gst_object_unref (basertppayload);
++
++  return caps;
++}
++
++static gboolean
++gst_basertppayload_event (GstPad * pad, GstEvent * event)
++{
++  GstBaseRTPPayload *basertppayload;
++  GstBaseRTPPayloadClass *basertppayload_class;
++  gboolean res;
++
++  basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad));
++  basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);
++
++  if (basertppayload_class->handle_event) {
++    res = basertppayload_class->handle_event (pad, event);
++    if (res)
++      goto done;
++  }
++
++  switch (GST_EVENT_TYPE (event)) {
++    case GST_EVENT_FLUSH_START:
++      res = gst_pad_event_default (pad, event);
++      break;
++    case GST_EVENT_FLUSH_STOP:
++      res = gst_pad_event_default (pad, event);
++      gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED);
++      break;
++    case GST_EVENT_NEWSEGMENT:
++    {
++      gboolean update;
++      gdouble rate;
++      GstFormat fmt;
++      gint64 start, stop, position;
++
++      gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop,
++          &position);
++      gst_segment_set_newsegment (&basertppayload->segment, update, rate, fmt,
++          start, stop, position);
++
++      /* fallthrough */
++    }
++    default:
++      res = gst_pad_event_default (pad, event);
++      break;
++  }
++
++done:
++  gst_object_unref (basertppayload);
++
++  return res;
++}
++
++
++static GstFlowReturn
++gst_basertppayload_chain (GstPad * pad, GstBuffer * buffer)
++{
++  GstBaseRTPPayload *basertppayload;
++  GstBaseRTPPayloadClass *basertppayload_class;
++  GstFlowReturn ret;
++
++  basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad));
++  basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);
++
++  if (!basertppayload_class->handle_buffer)
++    goto no_function;
++
++  ret = basertppayload_class->handle_buffer (basertppayload, buffer);
++
++  gst_object_unref (basertppayload);
++
++  return ret;
++
++  /* ERRORS */
++no_function:
++  {
++    GST_ELEMENT_ERROR (basertppayload, STREAM, NOT_IMPLEMENTED, (NULL),
++        ("subclass did not implement handle_buffer function"));
++    gst_object_unref (basertppayload);
++    gst_buffer_unref (buffer);
++    return GST_FLOW_ERROR;
++  }
++}
++
++/**
++ * gst_basertppayload_set_options:
++ * @payload: a #GstBaseRTPPayload
++ * @media: the media type (typically "audio" or "video")
++ * @dynamic: if the payload type is dynamic
++ * @encoding_name: the encoding name
++ * @clock_rate: the clock rate of the media
++ *
++ * Set the rtp options of the payloader. These options will be set in the caps
++ * of the payloader. Subclasses must call this method before calling
++ * gst_basertppayload_push() or gst_basertppayload_set_outcaps().
++ */
++void
++gst_basertppayload_set_options (GstBaseRTPPayload * payload,
++    const gchar * media, gboolean dynamic, const gchar * encoding_name,
++    guint32 clock_rate)
++{
++  g_return_if_fail (payload != NULL);
++  g_return_if_fail (clock_rate != 0);
++
++  g_free (payload->media);
++  payload->media = g_strdup (media);
++  payload->dynamic = dynamic;
++  g_free (payload->encoding_name);
++  payload->encoding_name = g_strdup (encoding_name);
++  payload->clock_rate = clock_rate;
++}
++
++static gboolean
++copy_fixed (GQuark field_id, const GValue * value, GstStructure * dest)
++{
++  if (gst_value_is_fixed (value)) {
++    gst_structure_id_set_value (dest, field_id, value);
++  }
++  return TRUE;
++}
++
++static void
++update_max_ptime (GstBaseRTPPayload * basertppayload)
++{
++  if (basertppayload->priv->caps_max_ptime != -1 &&
++      basertppayload->priv->prop_max_ptime != -1)
++    basertppayload->max_ptime = MIN (basertppayload->priv->caps_max_ptime,
++        basertppayload->priv->prop_max_ptime);
++  else if (basertppayload->priv->caps_max_ptime != -1)
++    basertppayload->max_ptime = basertppayload->priv->caps_max_ptime;
++  else if (basertppayload->priv->prop_max_ptime != -1)
++    basertppayload->max_ptime = basertppayload->priv->prop_max_ptime;
++  else
++    basertppayload->max_ptime = DEFAULT_MAX_PTIME;
++}
++
++/**
++ * gst_basertppayload_set_outcaps:
++ * @payload: a #GstBaseRTPPayload
++ * @fieldname: the first field name or %NULL
++ * @...: field values
++ *
++ * Configure the output caps with the optional parameters.
++ *
++ * Variable arguments should be in the form field name, field type
++ * (as a GType), value(s).  The last variable argument should be NULL.
++ *
++ * Returns: %TRUE if the caps could be set.
++ */
++gboolean
++gst_basertppayload_set_outcaps (GstBaseRTPPayload * payload,
++    const gchar * fieldname, ...)
++{
++  GstCaps *srccaps, *peercaps;
++  gboolean res;
++
++  /* fill in the defaults, their properties cannot be negotiated. */
++  srccaps = gst_caps_new_simple ("application/x-rtp",
++      "media", G_TYPE_STRING, payload->media,
++      "clock-rate", G_TYPE_INT, payload->clock_rate,
++      "encoding-name", G_TYPE_STRING, payload->encoding_name, NULL);
++
++  GST_DEBUG_OBJECT (payload, "defaults: %" GST_PTR_FORMAT, srccaps);
++
++  if (fieldname) {
++    va_list varargs;
++
++    /* override with custom properties */
++    va_start (varargs, fieldname);
++    gst_caps_set_simple_valist (srccaps, fieldname, varargs);
++    va_end (varargs);
++
++    GST_DEBUG_OBJECT (payload, "custom added: %" GST_PTR_FORMAT, srccaps);
++  }
++
++  payload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
++  payload->abidata.ABI.ptime = 0;
++
++  /* the peer caps can override some of the defaults */
++  peercaps = gst_pad_peer_get_caps (payload->srcpad);
++  if (peercaps == NULL) {
++    /* no peer caps, just add the other properties */
++    gst_caps_set_simple (srccaps,
++        "payload", G_TYPE_INT, GST_BASE_RTP_PAYLOAD_PT (payload),
++        "ssrc", G_TYPE_UINT, payload->current_ssrc,
++        "clock-base", G_TYPE_UINT, payload->ts_base,
++        "seqnum-base", G_TYPE_UINT, payload->seqnum_base, NULL);
++
++    GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps);
++  } else {
++    GstCaps *temp;
++    GstStructure *s, *d;
++    const GValue *value;
++    gint pt;
++    guint max_ptime, ptime;
++
++    /* peer provides caps we can use to fixate, intersect. This always returns a
++     * writable caps. */
++    temp = gst_caps_intersect (srccaps, peercaps);
++    gst_caps_unref (srccaps);
++    gst_caps_unref (peercaps);
++
++    if (gst_caps_is_empty (temp)) {
++      gst_caps_unref (temp);
++      return FALSE;
++    }
++
++    /* now fixate, start by taking the first caps */
++    gst_caps_truncate (temp);
++
++    /* get first structure */
++    s = gst_caps_get_structure (temp, 0);
++
++    if (gst_structure_get_uint (s, "maxptime", &max_ptime))
++      payload->priv->caps_max_ptime = max_ptime * GST_MSECOND;
++
++    if (gst_structure_get_uint (s, "ptime", &ptime))
++      payload->abidata.ABI.ptime = ptime * GST_MSECOND;
++
++    if (gst_structure_get_int (s, "payload", &pt)) {
++      /* use peer pt */
++      GST_BASE_RTP_PAYLOAD_PT (payload) = pt;
++      GST_LOG_OBJECT (payload, "using peer pt %d", pt);
++    } else {
++      if (gst_structure_has_field (s, "payload")) {
++        /* can only fixate if there is a field */
++        gst_structure_fixate_field_nearest_int (s, "payload",
++            GST_BASE_RTP_PAYLOAD_PT (payload));
++        gst_structure_get_int (s, "payload", &pt);
++        GST_LOG_OBJECT (payload, "using peer pt %d", pt);
++      } else {
++        /* no pt field, use the internal pt */
++        pt = GST_BASE_RTP_PAYLOAD_PT (payload);
++        gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
++        GST_LOG_OBJECT (payload, "using internal pt %d", pt);
++      }
++    }
++
++    if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) {
++      value = gst_structure_get_value (s, "ssrc");
++      payload->current_ssrc = g_value_get_uint (value);
++      GST_LOG_OBJECT (payload, "using peer ssrc %08x", payload->current_ssrc);
++    } else {
++      /* FIXME, fixate_nearest_uint would be even better */
++      gst_structure_set (s, "ssrc", G_TYPE_UINT, payload->current_ssrc, NULL);
++      GST_LOG_OBJECT (payload, "using internal ssrc %08x",
++          payload->current_ssrc);
++    }
++
++    if (gst_structure_has_field_typed (s, "clock-base", G_TYPE_UINT)) {
++      value = gst_structure_get_value (s, "clock-base");
++      payload->ts_base = g_value_get_uint (value);
++      GST_LOG_OBJECT (payload, "using peer clock-base %u", payload->ts_base);
++    } else {
++      /* FIXME, fixate_nearest_uint would be even better */
++      gst_structure_set (s, "clock-base", G_TYPE_UINT, payload->ts_base, NULL);
++      GST_LOG_OBJECT (payload, "using internal clock-base %u",
++          payload->ts_base);
++    }
++    if (gst_structure_has_field_typed (s, "seqnum-base", G_TYPE_UINT)) {
++      value = gst_structure_get_value (s, "seqnum-base");
++      payload->seqnum_base = g_value_get_uint (value);
++      GST_LOG_OBJECT (payload, "using peer seqnum-base %u",
++          payload->seqnum_base);
++    } else {
++      /* FIXME, fixate_nearest_uint would be even better */
++      gst_structure_set (s, "seqnum-base", G_TYPE_UINT, payload->seqnum_base,
++          NULL);
++      GST_LOG_OBJECT (payload, "using internal seqnum-base %u",
++          payload->seqnum_base);
++    }
++
++    /* make the target caps by copying over all the fixed caps, removing the
++     * unfixed caps. */
++    srccaps = gst_caps_new_simple (gst_structure_get_name (s), NULL);
++    d = gst_caps_get_structure (srccaps, 0);
++
++    gst_structure_foreach (s, (GstStructureForeachFunc) copy_fixed, d);
++
++    gst_caps_unref (temp);
++
++    GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps);
++  }
++
++  update_max_ptime (payload);
++
++  res = gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), srccaps);
++  gst_caps_unref (srccaps);
++
++  return res;
++}
++
++/**
++ * gst_basertppayload_is_filled:
++ * @payload: a #GstBaseRTPPayload
++ * @size: the size of the packet
++ * @duration: the duration of the packet
++ *
++ * Check if the packet with @size and @duration would exceed the configured
++ * maximum size.
++ *
++ * Returns: %TRUE if the packet of @size and @duration would exceed the
++ * configured MTU or max_ptime.
++ */
++gboolean
++gst_basertppayload_is_filled (GstBaseRTPPayload * payload,
++    guint size, GstClockTime duration)
++{
++  if (size > payload->mtu)
++    return TRUE;
++
++  if (payload->max_ptime != -1 && duration >= payload->max_ptime)
++    return TRUE;
++
++  return FALSE;
++}
++
++typedef struct
++{
++  GstBaseRTPPayload *payload;
++  guint32 ssrc;
++  guint16 seqnum;
++  guint8 pt;
++  GstCaps *caps;
++  GstClockTime timestamp;
++  guint64 offset;
++  guint32 rtptime;
++} HeaderData;
++
++static GstBufferListItem
++find_timestamp (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
++{
++  data->timestamp = GST_BUFFER_TIMESTAMP (*buffer);
++  data->offset = GST_BUFFER_OFFSET (*buffer);
++
++  /* stop when we find a timestamp. We take whatever offset is associated with
++   * the timestamp (if any) to do perfect timestamps when we need to. */
++  if (data->timestamp != -1)
++    return GST_BUFFER_LIST_END;
++  else
++    return GST_BUFFER_LIST_CONTINUE;
++}
++
++static GstBufferListItem
++set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
++{
++  gst_rtp_buffer_set_ssrc (*buffer, data->ssrc);
++  gst_rtp_buffer_set_payload_type (*buffer, data->pt);
++  gst_rtp_buffer_set_seq (*buffer, data->seqnum);
++  gst_rtp_buffer_set_timestamp (*buffer, data->rtptime);
++  gst_buffer_set_caps (*buffer, data->caps);
++  /* increment the seqnum for each buffer */
++  data->seqnum++;
++
++  return GST_BUFFER_LIST_SKIP_GROUP;
++}
++
++/* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer
++ * before the buffer is pushed. */
++static GstFlowReturn
++gst_basertppayload_prepare_push (GstBaseRTPPayload * payload,
++    gpointer obj, gboolean is_list)
++{
++  GstBaseRTPPayloadPrivate *priv;
++  HeaderData data;
++
++  if (payload->clock_rate == 0)
++    goto no_rate;
++
++  priv = payload->priv;
++
++  /* update first, so that the property is set to the last
++   * seqnum pushed */
++  payload->seqnum = priv->next_seqnum;
++
++  /* fill in the fields we want to set on all headers */
++  data.payload = payload;
++  data.seqnum = payload->seqnum;
++  data.ssrc = payload->current_ssrc;
++  data.pt = payload->pt;
++  data.caps = GST_PAD_CAPS (payload->srcpad);
++
++  /* find the first buffer with a timestamp */
++  if (is_list) {
++    data.timestamp = -1;
++    data.offset = GST_BUFFER_OFFSET_NONE;
++    gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj),
++        (GstBufferListFunc) find_timestamp, &data);
++  } else {
++    data.timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (obj));
++    data.offset = GST_BUFFER_OFFSET (GST_BUFFER_CAST (obj));
++  }
++
++  /* convert to RTP time */
++  if (priv->perfect_rtptime && data.offset != GST_BUFFER_OFFSET_NONE) {
++    /* if we have an offset, use that for making an RTP timestamp */
++    data.rtptime = payload->ts_base + data.offset;
++    GST_LOG_OBJECT (payload,
++        "Using offset %" G_GUINT64_FORMAT " for RTP timestamp", data.offset);
++  } else if (GST_CLOCK_TIME_IS_VALID (data.timestamp)) {
++    gint64 rtime;
++
++    /* no offset, use the gstreamer timestamp */
++    rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME,
++        data.timestamp);
++
++    GST_LOG_OBJECT (payload,
++        "Using running_time %" GST_TIME_FORMAT " for RTP timestamp",
++        GST_TIME_ARGS (rtime));
++
++    rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND);
++
++    /* add running_time in clock-rate units to the base timestamp */
++    data.rtptime = payload->ts_base + rtime;
++  } else {
++    GST_LOG_OBJECT (payload,
++        "Using previous RTP timestamp %" G_GUINT32_FORMAT, payload->timestamp);
++    /* no timestamp to convert, take previous timestamp */
++    data.rtptime = payload->timestamp;
++  }
++
++  /* set ssrc, payload type, seq number, caps and rtptime */
++  if (is_list) {
++    gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj),
++        (GstBufferListFunc) set_headers, &data);
++  } else {
++    GstBuffer *buf = GST_BUFFER_CAST (obj);
++    set_headers (&buf, 0, 0, &data);
++  }
++
++  priv->next_seqnum = data.seqnum;
++  payload->timestamp = data.rtptime;
++
++  GST_LOG_OBJECT (payload,
++      "Preparing to push packet with size %d, seq=%d, rtptime=%u, timestamp %"
++      GST_TIME_FORMAT, (is_list) ? -1 :
++      GST_BUFFER_SIZE (GST_BUFFER (obj)), payload->seqnum, data.rtptime,
++      GST_TIME_ARGS (data.timestamp));
++
++  return GST_FLOW_OK;
++
++  /* ERRORS */
++no_rate:
++  {
++    GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL),
++        ("subclass did not specify clock-rate"));
++    return GST_FLOW_ERROR;
++  }
++}
++
++/**
++ * gst_basertppayload_push_list:
++ * @payload: a #GstBaseRTPPayload
++ * @list: a #GstBufferList
++ *
++ * Push @list to the peer element of the payloader. The SSRC, payload type,
++ * seqnum and timestamp of the RTP buffer will be updated first.
++ *
++ * This function takes ownership of @list.
++ *
++ * Returns: a #GstFlowReturn.
++ *
++ * Since: 0.10.24
++ */
++GstFlowReturn
++gst_basertppayload_push_list (GstBaseRTPPayload * payload, GstBufferList * list)
++{
++  GstFlowReturn res;
++
++  res = gst_basertppayload_prepare_push (payload, list, TRUE);
++
++  if (G_LIKELY (res == GST_FLOW_OK))
++    res = gst_pad_push_list (payload->srcpad, list);
++  else
++    gst_buffer_list_unref (list);
++
++  return res;
++}
++
++/**
++ * gst_basertppayload_push:
++ * @payload: a #GstBaseRTPPayload
++ * @buffer: a #GstBuffer
++ *
++ * Push @buffer to the peer element of the payloader. The SSRC, payload type,
++ * seqnum and timestamp of the RTP buffer will be updated first.
++ *
++ * This function takes ownership of @buffer.
++ *
++ * Returns: a #GstFlowReturn.
++ */
++GstFlowReturn
++gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer)
++{
++  GstFlowReturn res;
++
++  res = gst_basertppayload_prepare_push (payload, buffer, FALSE);
++
++  if (G_LIKELY (res == GST_FLOW_OK))
++    res = gst_pad_push (payload->srcpad, buffer);
++  else
++    gst_buffer_unref (buffer);
++
++  return res;
++}
++
++static void
++gst_basertppayload_set_property (GObject * object, guint prop_id,
++    const GValue * value, GParamSpec * pspec)
++{
++  GstBaseRTPPayload *basertppayload;
++  GstBaseRTPPayloadPrivate *priv;
++  gint64 val;
++
++  basertppayload = GST_BASE_RTP_PAYLOAD (object);
++  priv = basertppayload->priv;
++
++  switch (prop_id) {
++    case PROP_MTU:
++      basertppayload->mtu = g_value_get_uint (value);
++      break;
++    case PROP_PT:
++      basertppayload->pt = g_value_get_uint (value);
++      break;
++    case PROP_SSRC:
++      val = g_value_get_uint (value);
++      basertppayload->ssrc = val;
++      priv->ssrc_random = FALSE;
++      break;
++    case PROP_TIMESTAMP_OFFSET:
++      val = g_value_get_uint (value);
++      basertppayload->ts_offset = val;
++      priv->ts_offset_random = FALSE;
++      break;
++    case PROP_SEQNUM_OFFSET:
++      val = g_value_get_int (value);
++      basertppayload->seqnum_offset = val;
++      priv->seqnum_offset_random = (val == -1);
++      GST_DEBUG_OBJECT (basertppayload, "seqnum offset 0x%04x, random %d",
++          basertppayload->seqnum_offset, priv->seqnum_offset_random);
++      break;
++    case PROP_MAX_PTIME:
++      basertppayload->priv->prop_max_ptime = g_value_get_int64 (value);
++      update_max_ptime (basertppayload);
++      break;
++    case PROP_MIN_PTIME:
++      basertppayload->min_ptime = g_value_get_int64 (value);
++      break;
++    case PROP_PERFECT_RTPTIME:
++      priv->perfect_rtptime = g_value_get_boolean (value);
++      break;
++    case PROP_PTIME_MULTIPLE:
++      basertppayload->abidata.ABI.ptime_multiple = g_value_get_int64 (value);
++      break;
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++  }
++}
++
++static void
++gst_basertppayload_get_property (GObject * object, guint prop_id,
++    GValue * value, GParamSpec * pspec)
++{
++  GstBaseRTPPayload *basertppayload;
++  GstBaseRTPPayloadPrivate *priv;
++
++  basertppayload = GST_BASE_RTP_PAYLOAD (object);
++  priv = basertppayload->priv;
++
++  switch (prop_id) {
++    case PROP_MTU:
++      g_value_set_uint (value, basertppayload->mtu);
++      break;
++    case PROP_PT:
++      g_value_set_uint (value, basertppayload->pt);
++      break;
++    case PROP_SSRC:
++      if (priv->ssrc_random)
++        g_value_set_uint (value, -1);
++      else
++        g_value_set_uint (value, basertppayload->ssrc);
++      break;
++    case PROP_TIMESTAMP_OFFSET:
++      if (priv->ts_offset_random)
++        g_value_set_uint (value, -1);
++      else
++        g_value_set_uint (value, (guint32) basertppayload->ts_offset);
++      break;
++    case PROP_SEQNUM_OFFSET:
++      if (priv->seqnum_offset_random)
++        g_value_set_int (value, -1);
++      else
++        g_value_set_int (value, (guint16) basertppayload->seqnum_offset);
++      break;
++    case PROP_MAX_PTIME:
++      g_value_set_int64 (value, basertppayload->max_ptime);
++      break;
++    case PROP_MIN_PTIME:
++      g_value_set_int64 (value, basertppayload->min_ptime);
++      break;
++    case PROP_TIMESTAMP:
++      g_value_set_uint (value, basertppayload->timestamp);
++      break;
++    case PROP_SEQNUM:
++      g_value_set_uint (value, basertppayload->seqnum);
++      break;
++    case PROP_PERFECT_RTPTIME:
++      g_value_set_boolean (value, priv->perfect_rtptime);
++      break;
++    case PROP_PTIME_MULTIPLE:
++      g_value_set_int64 (value, basertppayload->abidata.ABI.ptime_multiple);
++      break;
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++  }
++}
++
++static GstStateChangeReturn
++gst_basertppayload_change_state (GstElement * element,
++    GstStateChange transition)
++{
++  GstBaseRTPPayload *basertppayload;
++  GstBaseRTPPayloadPrivate *priv;
++  GstStateChangeReturn ret;
++
++  basertppayload = GST_BASE_RTP_PAYLOAD (element);
++  priv = basertppayload->priv;
++
++  switch (transition) {
++    case GST_STATE_CHANGE_NULL_TO_READY:
++      break;
++    case GST_STATE_CHANGE_READY_TO_PAUSED:
++      gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED);
++
++      if (priv->seqnum_offset_random)
++        basertppayload->seqnum_base = g_random_int_range (0, G_MAXUINT16);
++      else
++        basertppayload->seqnum_base = basertppayload->seqnum_offset;
++      priv->next_seqnum = basertppayload->seqnum_base;
++      basertppayload->seqnum = basertppayload->seqnum_base;
++
++      if (priv->ssrc_random)
++        basertppayload->current_ssrc = g_random_int ();
++      else
++        basertppayload->current_ssrc = basertppayload->ssrc;
++
++      if (priv->ts_offset_random)
++        basertppayload->ts_base = g_random_int ();
++      else
++        basertppayload->ts_base = basertppayload->ts_offset;
++      basertppayload->timestamp = basertppayload->ts_base;
++      break;
++    default:
++      break;
++  }
++
++  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
++
++  switch (transition) {
++    case GST_STATE_CHANGE_READY_TO_NULL:
++      break;
++    default:
++      break;
++  }
++  return ret;
++}
index 0000000,0000000..adeb449
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++*************** struct _GstBaseRTPPayloadPrivate
++*** 48,53 ****
++    guint16 next_seqnum;
++    gboolean perfect_rtptime;
++    gboolean timestamp_valid;
++  
++    gint64 prop_max_ptime;
++    gint64 caps_max_ptime;
++--- 48,54 ----
++    guint16 next_seqnum;
++    gboolean perfect_rtptime;
++    gboolean timestamp_valid;
+++   gboolean notified_first_timestamp;
++  
++    gint64 prop_max_ptime;
++    gint64 caps_max_ptime;
index 0000000,0000000..87b36d4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1403 @@@
++/* GStreamer
++ * Copyright (C) <2005> Philippe Khalaf <burger@speedy.org>
++ * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/**
++ * SECTION:gstrtpbuffer
++ * @short_description: Helper methods for dealing with RTP buffers
++ * @see_also: #GstBaseRTPPayload, #GstBaseRTPDepayload, gstrtcpbuffer
++ *
++ * <refsect2>
++ * <para>
++ * The GstRTPBuffer helper functions makes it easy to parse and create regular 
++ * #GstBuffer objects that contain RTP payloads. These buffers are typically of
++ * 'application/x-rtp' #GstCaps.
++ * </para>
++ * </refsect2>
++ *
++ * Last reviewed on 2006-07-17 (0.10.10)
++ */
++
++#include "gstrtpbuffer.h"
++
++#include <stdlib.h>
++#include <string.h>
++
++#define GST_RTP_HEADER_LEN 12
++
++/* Note: we use bitfields here to make sure the compiler doesn't add padding
++ * between fields on certain architectures; can't assume aligned access either
++ */
++typedef struct _GstRTPHeader
++{
++#if G_BYTE_ORDER == G_LITTLE_ENDIAN
++  unsigned int csrc_count:4;    /* CSRC count */
++  unsigned int extension:1;     /* header extension flag */
++  unsigned int padding:1;       /* padding flag */
++  unsigned int version:2;       /* protocol version */
++  unsigned int payload_type:7;  /* payload type */
++  unsigned int marker:1;        /* marker bit */
++#elif G_BYTE_ORDER == G_BIG_ENDIAN
++  unsigned int version:2;       /* protocol version */
++  unsigned int padding:1;       /* padding flag */
++  unsigned int extension:1;     /* header extension flag */
++  unsigned int csrc_count:4;    /* CSRC count */
++  unsigned int marker:1;        /* marker bit */
++  unsigned int payload_type:7;  /* payload type */
++#else
++#error "G_BYTE_ORDER should be big or little endian."
++#endif
++  unsigned int seq:16;          /* sequence number */
++  unsigned int timestamp:32;    /* timestamp */
++  unsigned int ssrc:32;         /* synchronization source */
++  guint8 csrclist[4];           /* optional CSRC list, 32 bits each */
++} GstRTPHeader;
++
++#define GST_RTP_HEADER_VERSION(data)      (((GstRTPHeader *)(data))->version)
++#define GST_RTP_HEADER_PADDING(data)      (((GstRTPHeader *)(data))->padding)
++#define GST_RTP_HEADER_EXTENSION(data)    (((GstRTPHeader *)(data))->extension)
++#define GST_RTP_HEADER_CSRC_COUNT(data)   (((GstRTPHeader *)(data))->csrc_count)
++#define GST_RTP_HEADER_MARKER(data)       (((GstRTPHeader *)(data))->marker)
++#define GST_RTP_HEADER_PAYLOAD_TYPE(data) (((GstRTPHeader *)(data))->payload_type)
++#define GST_RTP_HEADER_SEQ(data)          (((GstRTPHeader *)(data))->seq)
++#define GST_RTP_HEADER_TIMESTAMP(data)    (((GstRTPHeader *)(data))->timestamp)
++#define GST_RTP_HEADER_SSRC(data)         (((GstRTPHeader *)(data))->ssrc)
++#define GST_RTP_HEADER_CSRC_LIST_OFFSET(data,i)        \
++    data + G_STRUCT_OFFSET(GstRTPHeader, csrclist) +   \
++    ((i) * sizeof(guint32))
++#define GST_RTP_HEADER_CSRC_SIZE(data)   (GST_RTP_HEADER_CSRC_COUNT(data) * sizeof (guint32))
++
++typedef enum
++{
++  PAYLOAD_TYPE,
++  SEQ,
++  TIMESTAMP,
++  SSRC,
++  NO_MORE
++} rtp_header_data_type;
++
++static gboolean validate_data (guint8 * data, guint len, guint8 * payload,
++    guint payload_len);
++static guint8 *gst_rtp_buffer_list_get_data (GstBufferList * list);
++static void gst_rtp_buffer_list_set_rtp_headers (GstBufferList * list,
++    gpointer data, rtp_header_data_type type);
++static void gst_rtp_buffer_list_set_data (guint8 * rtp_header, gpointer data,
++    rtp_header_data_type type);
++
++/**
++ * gst_rtp_buffer_allocate_data:
++ * @buffer: a #GstBuffer
++ * @payload_len: the length of the payload
++ * @pad_len: the amount of padding
++ * @csrc_count: the number of CSRC entries
++ *
++ * Allocate enough data in @buffer to hold an RTP packet with @csrc_count CSRCs,
++ * a payload length of @payload_len and padding of @pad_len.
++ * MALLOCDATA of @buffer will be overwritten and will not be freed. 
++ * All other RTP header fields will be set to 0/FALSE.
++ */
++void
++gst_rtp_buffer_allocate_data (GstBuffer * buffer, guint payload_len,
++    guint8 pad_len, guint8 csrc_count)
++{
++  guint len;
++  guint8 *data;
++
++  g_return_if_fail (csrc_count <= 15);
++  g_return_if_fail (GST_IS_BUFFER (buffer));
++
++  len = GST_RTP_HEADER_LEN + csrc_count * sizeof (guint32)
++      + payload_len + pad_len;
++
++  data = g_malloc (len);
++  GST_BUFFER_MALLOCDATA (buffer) = data;
++  GST_BUFFER_DATA (buffer) = data;
++  GST_BUFFER_SIZE (buffer) = len;
++
++  /* fill in defaults */
++  GST_RTP_HEADER_VERSION (data) = GST_RTP_VERSION;
++  GST_RTP_HEADER_PADDING (data) = FALSE;
++  GST_RTP_HEADER_EXTENSION (data) = FALSE;
++  GST_RTP_HEADER_CSRC_COUNT (data) = csrc_count;
++  memset (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, 0), 0,
++      csrc_count * sizeof (guint32));
++  GST_RTP_HEADER_MARKER (data) = FALSE;
++  GST_RTP_HEADER_PAYLOAD_TYPE (data) = 0;
++  GST_RTP_HEADER_SEQ (data) = 0;
++  GST_RTP_HEADER_TIMESTAMP (data) = 0;
++  GST_RTP_HEADER_SSRC (data) = 0;
++}
++
++/**
++ * gst_rtp_buffer_new_take_data:
++ * @data: data for the new buffer
++ * @len: the length of data
++ *
++ * Create a new buffer and set the data and size of the buffer to @data and @len
++ * respectively. @data will be freed when the buffer is unreffed, so this
++ * function transfers ownership of @data to the new buffer.
++ *
++ * Returns: A newly allocated buffer with @data and of size @len.
++ */
++GstBuffer *
++gst_rtp_buffer_new_take_data (gpointer data, guint len)
++{
++  GstBuffer *result;
++
++  g_return_val_if_fail (data != NULL, NULL);
++  g_return_val_if_fail (len > 0, NULL);
++
++  result = gst_buffer_new ();
++
++  GST_BUFFER_MALLOCDATA (result) = data;
++  GST_BUFFER_DATA (result) = data;
++  GST_BUFFER_SIZE (result) = len;
++
++  return result;
++}
++
++/**
++ * gst_rtp_buffer_new_copy_data:
++ * @data: data for the new buffer
++ * @len: the length of data
++ *
++ * Create a new buffer and set the data to a copy of @len
++ * bytes of @data and the size to @len. The data will be freed when the buffer
++ * is freed.
++ *
++ * Returns: A newly allocated buffer with a copy of @data and of size @len.
++ */
++GstBuffer *
++gst_rtp_buffer_new_copy_data (gpointer data, guint len)
++{
++  return gst_rtp_buffer_new_take_data (g_memdup (data, len), len);
++}
++
++/**
++ * gst_rtp_buffer_new_allocate:
++ * @payload_len: the length of the payload
++ * @pad_len: the amount of padding
++ * @csrc_count: the number of CSRC entries
++ *
++ * Allocate a new #Gstbuffer with enough data to hold an RTP packet with @csrc_count CSRCs,
++ * a payload length of @payload_len and padding of @pad_len.
++ * All other RTP header fields will be set to 0/FALSE.
++ *
++ * Returns: A newly allocated buffer that can hold an RTP packet with given
++ * parameters.
++ */
++GstBuffer *
++gst_rtp_buffer_new_allocate (guint payload_len, guint8 pad_len,
++    guint8 csrc_count)
++{
++  GstBuffer *result;
++
++  g_return_val_if_fail (csrc_count <= 15, NULL);
++
++  result = gst_buffer_new ();
++  gst_rtp_buffer_allocate_data (result, payload_len, pad_len, csrc_count);
++
++  return result;
++}
++
++/**
++ * gst_rtp_buffer_new_allocate_len:
++ * @packet_len: the total length of the packet
++ * @pad_len: the amount of padding
++ * @csrc_count: the number of CSRC entries
++ *
++ * Create a new #GstBuffer that can hold an RTP packet that is exactly
++ * @packet_len long. The length of the payload depends on @pad_len and
++ * @csrc_count and can be calculated with gst_rtp_buffer_calc_payload_len().
++ * All RTP header fields will be set to 0/FALSE.
++ *
++ * Returns: A newly allocated buffer that can hold an RTP packet of @packet_len.
++ */
++GstBuffer *
++gst_rtp_buffer_new_allocate_len (guint packet_len, guint8 pad_len,
++    guint8 csrc_count)
++{
++  guint len;
++
++  g_return_val_if_fail (csrc_count <= 15, NULL);
++
++  len = gst_rtp_buffer_calc_payload_len (packet_len, pad_len, csrc_count);
++
++  return gst_rtp_buffer_new_allocate (len, pad_len, csrc_count);
++}
++
++/**
++ * gst_rtp_buffer_calc_header_len:
++ * @csrc_count: the number of CSRC entries
++ *
++ * Calculate the header length of an RTP packet with @csrc_count CSRC entries.
++ * An RTP packet can have at most 15 CSRC entries.
++ *
++ * Returns: The length of an RTP header with @csrc_count CSRC entries.
++ */
++guint
++gst_rtp_buffer_calc_header_len (guint8 csrc_count)
++{
++  g_return_val_if_fail (csrc_count <= 15, 0);
++
++  return GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32));
++}
++
++/**
++ * gst_rtp_buffer_calc_packet_len:
++ * @payload_len: the length of the payload
++ * @pad_len: the amount of padding
++ * @csrc_count: the number of CSRC entries
++ *
++ * Calculate the total length of an RTP packet with a payload size of @payload_len,
++ * a padding of @pad_len and a @csrc_count CSRC entries.
++ *
++ * Returns: The total length of an RTP header with given parameters.
++ */
++guint
++gst_rtp_buffer_calc_packet_len (guint payload_len, guint8 pad_len,
++    guint8 csrc_count)
++{
++  g_return_val_if_fail (csrc_count <= 15, 0);
++
++  return payload_len + GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32))
++      + pad_len;
++}
++
++/**
++ * gst_rtp_buffer_calc_payload_len:
++ * @packet_len: the length of the total RTP packet
++ * @pad_len: the amount of padding
++ * @csrc_count: the number of CSRC entries
++ *
++ * Calculate the length of the payload of an RTP packet with size @packet_len,
++ * a padding of @pad_len and a @csrc_count CSRC entries.
++ *
++ * Returns: The length of the payload of an RTP packet  with given parameters.
++ */
++guint
++gst_rtp_buffer_calc_payload_len (guint packet_len, guint8 pad_len,
++    guint8 csrc_count)
++{
++  g_return_val_if_fail (csrc_count <= 15, 0);
++
++  return packet_len - GST_RTP_HEADER_LEN - (csrc_count * sizeof (guint32))
++      - pad_len;
++}
++
++/**
++ * gst_rtp_buffer_validate_data:
++ * @data: the data to validate
++ * @len: the length of @data to validate
++ *
++ * Check if the @data and @size point to the data of a valid RTP packet.
++ * This function checks the length, version and padding of the packet data.
++ * Use this function to validate a packet before using the other functions in
++ * this module.
++ *
++ * Returns: TRUE if the data points to a valid RTP packet.
++ */
++gboolean
++gst_rtp_buffer_validate_data (guint8 * data, guint len)
++{
++  return validate_data (data, len, NULL, 0);
++}
++
++/**
++ * gst_rtp_buffer_validate:
++ * @buffer: the buffer to validate
++ *
++ * Check if the data pointed to by @buffer is a valid RTP packet using
++ * validate_data().
++ * Use this function to validate a packet before using the other functions in
++ * this module.
++ *
++ * Returns: TRUE if @buffer is a valid RTP packet.
++ */
++gboolean
++gst_rtp_buffer_validate (GstBuffer * buffer)
++{
++  guint8 *data;
++  guint len;
++
++  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
++
++  data = GST_BUFFER_DATA (buffer);
++  len = GST_BUFFER_SIZE (buffer);
++
++  return validate_data (data, len, NULL, 0);
++}
++
++/**
++ * gst_rtp_buffer_list_validate:
++ * @list: the buffer list to validate
++ *
++ * Check if all RTP packets in the @list are valid using validate_data().
++ * Use this function to validate an list before using the other functions in
++ * this module.
++ *
++ * Returns: TRUE if @list consists only of valid RTP packets.
++ */
++gboolean
++gst_rtp_buffer_list_validate (GstBufferList * list)
++{
++  guint16 prev_seqnum = 0;
++  GstBufferListIterator *it;
++  guint i = 0;
++
++  g_return_val_if_fail (GST_IS_BUFFER_LIST (list), FALSE);
++
++  it = gst_buffer_list_iterate (list);
++  g_return_val_if_fail (it != NULL, FALSE);
++
++  /* iterate through all the RTP packets in the list */
++  while (gst_buffer_list_iterator_next_group (it)) {
++    GstBuffer *rtpbuf;
++    GstBuffer *paybuf;
++    guint8 *packet_header;
++    guint8 *packet_payload;
++    guint payload_size;
++    guint packet_size;
++
++    /* each group should consists of 2 buffers: one containing the RTP header
++     * and the other one the payload */
++    if (gst_buffer_list_iterator_n_buffers (it) != 2)
++      goto invalid_list;
++
++    /* get the RTP header */
++    rtpbuf = gst_buffer_list_iterator_next (it);
++    packet_header = GST_BUFFER_DATA (rtpbuf);
++    if (packet_header == NULL)
++      goto invalid_list;
++
++    /* get the payload */
++    paybuf = gst_buffer_list_iterator_next (it);
++    packet_payload = GST_BUFFER_DATA (paybuf);
++    if (packet_payload == NULL) {
++      goto invalid_list;
++    }
++    payload_size = GST_BUFFER_SIZE (paybuf);
++    if (payload_size == 0) {
++      goto invalid_list;
++    }
++
++    /* the size of the RTP packet within the current group */
++    packet_size = GST_BUFFER_SIZE (rtpbuf) + payload_size;
++
++    /* check the sequence number */
++    if (G_UNLIKELY (i == 0)) {
++      prev_seqnum = g_ntohs (GST_RTP_HEADER_SEQ (packet_header));
++      i++;
++    } else {
++      if (++prev_seqnum != g_ntohs (GST_RTP_HEADER_SEQ (packet_header)))
++        goto invalid_list;
++    }
++
++    /* validate packet */
++    if (!validate_data (packet_header, packet_size, packet_payload,
++            payload_size)) {
++      goto invalid_list;
++    }
++  }
++
++  gst_buffer_list_iterator_free (it);
++  return TRUE;
++
++invalid_list:
++  gst_buffer_list_iterator_free (it);
++  g_return_val_if_reached (FALSE);
++}
++
++/**
++ * validate_data:
++ * @data: the data to validate
++ * @len: the length of @data to validate
++ * @payload: the payload if @data represents the header only
++ * @payload_len: the len of the payload
++ *
++ * Checks if @data is a valid RTP packet.
++ *
++ * Returns: TRUE if @data is a valid RTP packet
++ */
++static gboolean
++validate_data (guint8 * data, guint len, guint8 * payload, guint payload_len)
++{
++  guint8 padding;
++  guint8 csrc_count;
++  guint header_len;
++  guint8 version;
++
++  g_return_val_if_fail (data != NULL, FALSE);
++
++  header_len = GST_RTP_HEADER_LEN;
++  if (G_UNLIKELY (len < header_len))
++    goto wrong_length;
++
++  /* check version */
++  version = (data[0] & 0xc0);
++  if (G_UNLIKELY (version != (GST_RTP_VERSION << 6)))
++    goto wrong_version;
++
++  /* calc header length with csrc */
++  csrc_count = (data[0] & 0x0f);
++  header_len += csrc_count * sizeof (guint32);
++
++  /* calc extension length when present. */
++  if (data[0] & 0x10) {
++    guint8 *extpos;
++    guint16 extlen;
++
++    /* this points to the extenstion bits and header length */
++    extpos = &data[header_len];
++
++    /* skip the header and check that we have enough space */
++    header_len += 4;
++    if (G_UNLIKELY (len < header_len))
++      goto wrong_length;
++
++    /* skip id */
++    extpos += 2;
++    /* read length as the number of 32 bits words */
++    extlen = GST_READ_UINT16_BE (extpos);
++
++    header_len += extlen * sizeof (guint32);
++  }
++
++  /* check for padding */
++  if (data[0] & 0x20) {
++    if (payload)
++      padding = payload[payload_len - 1];
++    else
++      padding = data[len - 1];
++  } else {
++    padding = 0;
++  }
++
++  /* check if padding and header not bigger than packet length */
++  if (G_UNLIKELY (len < padding + header_len))
++    goto wrong_padding;
++
++  return TRUE;
++
++  /* ERRORS */
++wrong_length:
++  {
++    GST_DEBUG ("len < header_len check failed (%d < %d)", len, header_len);
++    return FALSE;
++  }
++wrong_version:
++  {
++    GST_DEBUG ("version check failed (%d != %d)", version, GST_RTP_VERSION);
++    return FALSE;
++  }
++wrong_padding:
++  {
++    GST_DEBUG ("padding check failed (%d - %d < %d)", len, header_len, padding);
++    return FALSE;
++  }
++}
++
++/**
++ * gst_rtp_buffer_set_packet_len:
++ * @buffer: the buffer
++ * @len: the new packet length
++ *
++ * Set the total @buffer size to @len. The data in the buffer will be made
++ * larger if needed. Any padding will be removed from the packet. 
++ */
++void
++gst_rtp_buffer_set_packet_len (GstBuffer * buffer, guint len)
++{
++  guint oldlen;
++  guint8 *data;
++
++  oldlen = GST_BUFFER_SIZE (buffer);
++  data = GST_BUFFER_DATA (buffer);
++
++  if (oldlen < len) {
++    data = g_realloc (GST_BUFFER_MALLOCDATA (buffer), len);
++    GST_BUFFER_MALLOCDATA (buffer) = data;
++    GST_BUFFER_DATA (buffer) = data;
++  }
++  GST_BUFFER_SIZE (buffer) = len;
++
++  /* remove any padding */
++  GST_RTP_HEADER_PADDING (data) = FALSE;
++}
++
++/**
++ * gst_rtp_buffer_get_packet_len:
++ * @buffer: the buffer
++ *
++ * Return the total length of the packet in @buffer.
++ *
++ * Returns: The total length of the packet in @buffer.
++ */
++guint
++gst_rtp_buffer_get_packet_len (GstBuffer * buffer)
++{
++  return GST_BUFFER_SIZE (buffer);
++}
++
++/**
++ * gst_rtp_buffer_get_header_len:
++ * @buffer: the buffer
++ *
++ * Return the total length of the header in @buffer. This include the length of
++ * the fixed header, the CSRC list and the extension header.
++ *
++ * Returns: The total length of the header in @buffer.
++ */
++guint
++gst_rtp_buffer_get_header_len (GstBuffer * buffer)
++{
++  guint len;
++  guint8 *data;
++
++  data = GST_BUFFER_DATA (buffer);
++
++  len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data);
++  if (GST_RTP_HEADER_EXTENSION (data))
++    len += GST_READ_UINT16_BE (data + len + 2) * 4 + 4;
++
++  return len;
++}
++
++/**
++ * gst_rtp_buffer_get_version:
++ * @buffer: the buffer
++ *
++ * Get the version number of the RTP packet in @buffer.
++ *
++ * Returns: The version of @buffer.
++ */
++guint8
++gst_rtp_buffer_get_version (GstBuffer * buffer)
++{
++  return GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer));
++}
++
++/**
++ * gst_rtp_buffer_set_version:
++ * @buffer: the buffer
++ * @version: the new version
++ *
++ * Set the version of the RTP packet in @buffer to @version.
++ */
++void
++gst_rtp_buffer_set_version (GstBuffer * buffer, guint8 version)
++{
++  g_return_if_fail (version < 0x04);
++
++  GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer)) = version;
++}
++
++/**
++ * gst_rtp_buffer_get_padding:
++ * @buffer: the buffer
++ *
++ * Check if the padding bit is set on the RTP packet in @buffer.
++ *
++ * Returns: TRUE if @buffer has the padding bit set.
++ */
++gboolean
++gst_rtp_buffer_get_padding (GstBuffer * buffer)
++{
++  return GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer));
++}
++
++/**
++ * gst_rtp_buffer_set_padding:
++ * @buffer: the buffer
++ * @padding: the new padding
++ *
++ * Set the padding bit on the RTP packet in @buffer to @padding.
++ */
++void
++gst_rtp_buffer_set_padding (GstBuffer * buffer, gboolean padding)
++{
++  GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer)) = padding;
++}
++
++/**
++ * gst_rtp_buffer_pad_to:
++ * @buffer: the buffer
++ * @len: the new amount of padding
++ *
++ * Set the amount of padding in the RTP packet in @buffer to
++ * @len. If @len is 0, the padding is removed.
++ *
++ * NOTE: This function does not work correctly.
++ */
++void
++gst_rtp_buffer_pad_to (GstBuffer * buffer, guint len)
++{
++  guint8 *data;
++
++  data = GST_BUFFER_DATA (buffer);
++
++  if (len > 0)
++    GST_RTP_HEADER_PADDING (data) = TRUE;
++  else
++    GST_RTP_HEADER_PADDING (data) = FALSE;
++
++  /* FIXME, set the padding byte at the end of the payload data */
++}
++
++/**
++ * gst_rtp_buffer_get_extension:
++ * @buffer: the buffer
++ *
++ * Check if the extension bit is set on the RTP packet in @buffer.
++ * 
++ * Returns: TRUE if @buffer has the extension bit set.
++ */
++gboolean
++gst_rtp_buffer_get_extension (GstBuffer * buffer)
++{
++  return GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer));
++}
++
++/**
++ * gst_rtp_buffer_set_extension:
++ * @buffer: the buffer
++ * @extension: the new extension
++ *
++ * Set the extension bit on the RTP packet in @buffer to @extension.
++ */
++void
++gst_rtp_buffer_set_extension (GstBuffer * buffer, gboolean extension)
++{
++  GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer)) = extension;
++}
++
++/**
++ * gst_rtp_buffer_get_extension_data:
++ * @buffer: the buffer
++ * @bits: location for result bits
++ * @data: location for data
++ * @wordlen: location for length of @data in 32 bits words
++ *
++ * Get the extension data. @bits will contain the extension 16 bits of custom
++ * data. @data will point to the data in the extension and @wordlen will contain
++ * the length of @data in 32 bits words.
++ *
++ * If @buffer did not contain an extension, this function will return %FALSE
++ * with @bits, @data and @wordlen unchanged.
++ * 
++ * Returns: TRUE if @buffer had the extension bit set.
++ *
++ * Since: 0.10.15
++ */
++gboolean
++gst_rtp_buffer_get_extension_data (GstBuffer * buffer, guint16 * bits,
++    gpointer * data, guint * wordlen)
++{
++  guint len;
++  guint8 *pdata;
++
++  pdata = GST_BUFFER_DATA (buffer);
++
++  if (!GST_RTP_HEADER_EXTENSION (pdata))
++    return FALSE;
++
++  /* move to the extension */
++  len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (pdata);
++  pdata += len;
++
++  if (bits)
++    *bits = GST_READ_UINT16_BE (pdata);
++  if (wordlen)
++    *wordlen = GST_READ_UINT16_BE (pdata + 2);
++  if (data)
++    *data = pdata + 4;
++
++  return TRUE;
++}
++
++/**
++ * gst_rtp_buffer_set_extension_data:
++ * @buffer: the buffer
++ * @bits: the bits specific for the extension
++ * @length: the length that counts the number of 32-bit words in
++ * the extension, excluding the extension header ( therefore zero is a valid length)
++ *
++ * Set the extension bit of the rtp buffer and fill in the @bits and @length of the
++ * extension header. It will refuse to set the extension data if the buffer is not
++ * large enough.
++ *
++ * Returns: True if done.
++ *
++ * Since : 0.10.18
++ */
++gboolean
++gst_rtp_buffer_set_extension_data (GstBuffer * buffer, guint16 bits,
++    guint16 length)
++{
++  guint32 min_size = 0;
++  guint8 *data;
++
++  data = GST_BUFFER_DATA (buffer);
++
++  /* check if the buffer is big enough to hold the extension */
++  min_size =
++      GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data) + 4 +
++      length * sizeof (guint32);
++  if (G_UNLIKELY (min_size > GST_BUFFER_SIZE (buffer)))
++    goto too_small;
++
++  /* now we can set the extension bit */
++  gst_rtp_buffer_set_extension (buffer, TRUE);
++
++  data += GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data);
++  GST_WRITE_UINT16_BE (data, bits);
++  GST_WRITE_UINT16_BE (data + 2, length);
++
++  return TRUE;
++
++  /* ERRORS */
++too_small:
++  {
++    g_warning
++        ("rtp buffer too small: need more than %d bytes but only have %d bytes",
++        min_size, GST_BUFFER_SIZE (buffer));
++    return FALSE;
++  }
++}
++
++/**
++ * gst_rtp_buffer_get_ssrc:
++ * @buffer: the buffer
++ *
++ * Get the SSRC of the RTP packet in @buffer.
++ * 
++ * Returns: the SSRC of @buffer in host order.
++ */
++guint32
++gst_rtp_buffer_get_ssrc (GstBuffer * buffer)
++{
++  return g_ntohl (GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)));
++}
++
++/**
++ * gst_rtp_buffer_list_get_ssrc:
++ * @list: the list
++ *
++ * Get the SSRC of the first RTP packet in @list.
++ * All RTP packets within @list have the same SSRC.
++ *
++ * Returns: the SSRC of @list in host order.
++ */
++guint32
++gst_rtp_buffer_list_get_ssrc (GstBufferList * list)
++{
++  guint8 *data;
++  data = gst_rtp_buffer_list_get_data (list);
++  g_return_val_if_fail (data != NULL, 0);
++  return g_ntohl (GST_RTP_HEADER_SSRC (data));
++}
++
++/**
++ * gst_rtp_buffer_set_ssrc:
++ * @buffer: the buffer
++ * @ssrc: the new SSRC
++ *
++ * Set the SSRC on the RTP packet in @buffer to @ssrc.
++ */
++void
++gst_rtp_buffer_set_ssrc (GstBuffer * buffer, guint32 ssrc)
++{
++  GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)) = g_htonl (ssrc);
++}
++
++/**
++ * gst_rtp_buffer_list_set_ssrc:
++ * @list: the buffer list
++ * @ssrc: the new SSRC
++ *
++ * Set the SSRC on each RTP packet in @list to @ssrc.
++ */
++void
++gst_rtp_buffer_list_set_ssrc (GstBufferList * list, guint32 ssrc)
++{
++  gst_rtp_buffer_list_set_rtp_headers (list, &ssrc, SSRC);
++}
++
++/**
++ * gst_rtp_buffer_get_csrc_count:
++ * @buffer: the buffer
++ *
++ * Get the CSRC count of the RTP packet in @buffer.
++ * 
++ * Returns: the CSRC count of @buffer.
++ */
++guint8
++gst_rtp_buffer_get_csrc_count (GstBuffer * buffer)
++{
++  return GST_RTP_HEADER_CSRC_COUNT (GST_BUFFER_DATA (buffer));
++}
++
++/**
++ * gst_rtp_buffer_get_csrc:
++ * @buffer: the buffer
++ * @idx: the index of the CSRC to get
++ *
++ * Get the CSRC at index @idx in @buffer.
++ * 
++ * Returns: the CSRC at index @idx in host order.
++ */
++guint32
++gst_rtp_buffer_get_csrc (GstBuffer * buffer, guint8 idx)
++{
++  guint8 *data;
++
++  data = GST_BUFFER_DATA (buffer);
++
++  g_return_val_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data), 0);
++
++  return GST_READ_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx));
++}
++
++/**
++ * gst_rtp_buffer_set_csrc:
++ * @buffer: the buffer
++ * @idx: the CSRC index to set
++ * @csrc: the CSRC in host order to set at @idx
++ *
++ * Modify the CSRC at index @idx in @buffer to @csrc.
++ */
++void
++gst_rtp_buffer_set_csrc (GstBuffer * buffer, guint8 idx, guint32 csrc)
++{
++  guint8 *data;
++
++  data = GST_BUFFER_DATA (buffer);
++
++  g_return_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data));
++
++  GST_WRITE_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx), csrc);
++}
++
++/**
++ * gst_rtp_buffer_get_marker:
++ * @buffer: the buffer
++ *
++ * Check if the marker bit is set on the RTP packet in @buffer.
++ *
++ * Returns: TRUE if @buffer has the marker bit set.
++ */
++gboolean
++gst_rtp_buffer_get_marker (GstBuffer * buffer)
++{
++  return GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer));
++}
++
++/**
++ * gst_rtp_buffer_set_marker:
++ * @buffer: the buffer
++ * @marker: the new marker
++ *
++ * Set the marker bit on the RTP packet in @buffer to @marker.
++ */
++void
++gst_rtp_buffer_set_marker (GstBuffer * buffer, gboolean marker)
++{
++  GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer)) = marker;
++}
++
++/**
++ * gst_rtp_buffer_get_payload_type:
++ * @buffer: the buffer
++ *
++ * Get the payload type of the RTP packet in @buffer.
++ *
++ * Returns: The payload type.
++ */
++guint8
++gst_rtp_buffer_get_payload_type (GstBuffer * buffer)
++{
++  return GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer));
++}
++
++/**
++ * gst_rtp_buffer_list_get_payload_type:
++ * @list: the list
++ *
++ * Get the payload type of the first RTP packet in @list.
++ * All packets in @list should have the same payload type.
++ *
++ * Returns: The payload type.
++ */
++guint8
++gst_rtp_buffer_list_get_payload_type (GstBufferList * list)
++{
++  guint8 *data;
++  data = gst_rtp_buffer_list_get_data (list);
++  g_return_val_if_fail (data != NULL, 0);
++  return GST_RTP_HEADER_PAYLOAD_TYPE (data);
++}
++
++/**
++ * gst_rtp_buffer_set_payload_type:
++ * @buffer: the buffer
++ * @payload_type: the new type
++ *
++ * Set the payload type of the RTP packet in @buffer to @payload_type.
++ */
++void
++gst_rtp_buffer_set_payload_type (GstBuffer * buffer, guint8 payload_type)
++{
++  g_return_if_fail (payload_type < 0x80);
++
++  GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer)) = payload_type;
++}
++
++/**
++ * gst_rtp_buffer_list_set_payload_type:
++ * @list: the buffer list
++ * @payload_type: the new type
++ *
++ * Set the payload type of each RTP packet in @list to @payload_type.
++ */
++void
++gst_rtp_buffer_list_set_payload_type (GstBufferList * list, guint8 payload_type)
++{
++  g_return_if_fail (payload_type < 0x80);
++
++  gst_rtp_buffer_list_set_rtp_headers (list, &payload_type, PAYLOAD_TYPE);
++}
++
++/**
++ * gst_rtp_buffer_get_seq:
++ * @buffer: the buffer
++ *
++ * Get the sequence number of the RTP packet in @buffer.
++ *
++ * Returns: The sequence number in host order.
++ */
++guint16
++gst_rtp_buffer_get_seq (GstBuffer * buffer)
++{
++  return g_ntohs (GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)));
++}
++
++/**
++ * gst_rtp_buffer_set_seq:
++ * @buffer: the buffer
++ * @seq: the new sequence number
++ *
++ * Set the sequence number of the RTP packet in @buffer to @seq.
++ */
++void
++gst_rtp_buffer_set_seq (GstBuffer * buffer, guint16 seq)
++{
++  GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)) = g_htons (seq);
++}
++
++/**
++ * gst_rtp_buffer_list_set_seq:
++ * @list: the buffer list
++ * @seq: the new sequence number
++ *
++ * Set the sequence number of each RTP packet in @list to @seq.
++ *
++ * Returns: The seq number of the last packet in the list + 1.
++ */
++guint16
++gst_rtp_buffer_list_set_seq (GstBufferList * list, guint16 seq)
++{
++  gst_rtp_buffer_list_set_rtp_headers (list, &seq, SEQ);
++  return seq;
++}
++
++/**
++ * gst_rtp_buffer_get_timestamp:
++ * @buffer: the buffer
++ *
++ * Get the timestamp of the RTP packet in @buffer.
++ *
++ * Returns: The timestamp in host order.
++ */
++guint32
++gst_rtp_buffer_get_timestamp (GstBuffer * buffer)
++{
++  return g_ntohl (GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)));
++}
++
++/**
++ * gst_rtp_buffer_list_get_timestamp:
++ * @list: the list
++ *
++ * Get the timestamp of the first RTP packet in @list.
++ * All packets within @list have the same timestamp.
++ *
++ * Returns: The timestamp in host order.
++ */
++guint32
++gst_rtp_buffer_list_get_timestamp (GstBufferList * list)
++{
++  guint8 *data;
++  data = gst_rtp_buffer_list_get_data (list);
++  g_return_val_if_fail (data != NULL, 0);
++  return g_ntohl (GST_RTP_HEADER_TIMESTAMP (data));
++}
++
++/**
++ * gst_rtp_buffer_set_timestamp:
++ * @buffer: the buffer
++ * @timestamp: the new timestamp
++ *
++ * Set the timestamp of the RTP packet in @buffer to @timestamp.
++ */
++void
++gst_rtp_buffer_set_timestamp (GstBuffer * buffer, guint32 timestamp)
++{
++  GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)) = g_htonl (timestamp);
++}
++
++/**
++ * gst_rtp_buffer_list_set_timestamp:
++ * @list: the buffer list
++ * @timestamp: the new timestamp
++ *
++ * Set the timestamp of each RTP packet in @list to @timestamp.
++ */
++void
++gst_rtp_buffer_list_set_timestamp (GstBufferList * list, guint32 timestamp)
++{
++  gst_rtp_buffer_list_set_rtp_headers (list, &timestamp, TIMESTAMP);
++}
++
++/**
++ * gst_rtp_buffer_get_payload_subbuffer:
++ * @buffer: the buffer
++ * @offset: the offset in the payload
++ * @len: the length in the payload
++ *
++ * Create a subbuffer of the payload of the RTP packet in @buffer. @offset bytes
++ * are skipped in the payload and the subbuffer will be of size @len.
++ * If @len is -1 the total payload starting from @offset if subbuffered.
++ *
++ * Returns: A new buffer with the specified data of the payload.
++ *
++ * Since: 0.10.10
++ */
++GstBuffer *
++gst_rtp_buffer_get_payload_subbuffer (GstBuffer * buffer, guint offset,
++    guint len)
++{
++  guint poffset, plen;
++
++  plen = gst_rtp_buffer_get_payload_len (buffer);
++  /* we can't go past the length */
++  if (G_UNLIKELY (offset >= plen))
++    goto wrong_offset;
++
++  /* apply offset */
++  poffset = gst_rtp_buffer_get_header_len (buffer) + offset;
++  plen -= offset;
++
++  /* see if we need to shrink the buffer based on @len */
++  if (len != -1 && len < plen)
++    plen = len;
++
++  return gst_buffer_create_sub (buffer, poffset, plen);
++
++  /* ERRORS */
++wrong_offset:
++  {
++    g_warning ("offset=%u should be less then plen=%u", offset, plen);
++    return NULL;
++  }
++}
++
++/**
++ * gst_rtp_buffer_get_payload_buffer:
++ * @buffer: the buffer
++ *
++ * Create a buffer of the payload of the RTP packet in @buffer. This function
++ * will internally create a subbuffer of @buffer so that a memcpy can be
++ * avoided.
++ *
++ * Returns: A new buffer with the data of the payload.
++ */
++GstBuffer *
++gst_rtp_buffer_get_payload_buffer (GstBuffer * buffer)
++{
++  return gst_rtp_buffer_get_payload_subbuffer (buffer, 0, -1);
++}
++
++/**
++ * gst_rtp_buffer_get_payload_len:
++ * @buffer: the buffer
++ *
++ * Get the length of the payload of the RTP packet in @buffer.
++ *
++ * Returns: The length of the payload in @buffer.
++ */
++guint
++gst_rtp_buffer_get_payload_len (GstBuffer * buffer)
++{
++  guint len, size;
++  guint8 *data;
++
++  size = GST_BUFFER_SIZE (buffer);
++  data = GST_BUFFER_DATA (buffer);
++
++  len = size - gst_rtp_buffer_get_header_len (buffer);
++
++  if (GST_RTP_HEADER_PADDING (data))
++    len -= data[size - 1];
++
++  return len;
++}
++
++/**
++ * gst_rtp_buffer_list_get_payload_len:
++ * @buffer: the buffer
++ *
++ * Get the length of the payload of the RTP packet in @list.
++ *
++ * Returns: The length of the payload in @list.
++ */
++guint
++gst_rtp_buffer_list_get_payload_len (GstBufferList * list)
++{
++  guint len = 0;
++  GstBufferListIterator *it;
++  it = gst_buffer_list_iterate (list);
++
++  while (gst_buffer_list_iterator_next_group (it)) {
++    guint i;
++    GstBuffer *buf;
++
++    i = 0;
++    while ((buf = gst_buffer_list_iterator_next (it))) {
++      /* skip the RTP header */
++      if (!i++)
++        continue;
++      /* take the size of the current buffer */
++      len += GST_BUFFER_SIZE (buf);
++    }
++  }
++
++  gst_buffer_list_iterator_free (it);
++
++  return len;
++}
++
++/**
++ * gst_rtp_buffer_get_payload:
++ * @buffer: the buffer
++ *
++ * Get a pointer to the payload data in @buffer. This pointer is valid as long
++ * as a reference to @buffer is held.
++ *
++ * Returns: A pointer to the payload data in @buffer.
++ */
++gpointer
++gst_rtp_buffer_get_payload (GstBuffer * buffer)
++{
++  return GST_BUFFER_DATA (buffer) + gst_rtp_buffer_get_header_len (buffer);
++}
++
++/**
++ * gst_rtp_buffer_default_clock_rate:
++ * @payload_type: the static payload type
++ *
++ * Get the default clock-rate for the static payload type @payload_type.
++ *
++ * Returns: the default clock rate or -1 if the payload type is not static or
++ * the clock-rate is undefined.
++ *
++ * Since: 0.10.13
++ */
++guint32
++gst_rtp_buffer_default_clock_rate (guint8 payload_type)
++{
++  const GstRTPPayloadInfo *info;
++  guint32 res;
++
++  info = gst_rtp_payload_info_for_pt (payload_type);
++  if (!info)
++    return -1;
++
++  res = info->clock_rate;
++  /* 0 means unknown so we have to return -1 from this function */
++  if (res == 0)
++    res = -1;
++
++  return res;
++}
++
++/**
++ * gst_rtp_buffer_compare_seqnum:
++ * @seqnum1: a sequence number
++ * @seqnum2: a sequence number
++ *
++ * Compare two sequence numbers, taking care of wraparounds. This function
++ * returns the difference between @seqnum1 and @seqnum2.
++ *
++ * Returns: a negative value if @seqnum1 is bigger than @seqnum2, 0 if they
++ * are equal or a positive value if @seqnum1 is smaller than @segnum2.
++ *
++ * Since: 0.10.15
++ */
++gint
++gst_rtp_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2)
++{
++  return (gint16) (seqnum2 - seqnum1);
++}
++
++/**
++ * gst_rtp_buffer_ext_timestamp:
++ * @exttimestamp: a previous extended timestamp
++ * @timestamp: a new timestamp
++ *
++ * Update the @exttimestamp field with @timestamp. For the first call of the
++ * method, @exttimestamp should point to a location with a value of -1.
++ *
++ * This function makes sure that the returned value is a constantly increasing
++ * value even in the case where there is a timestamp wraparound.
++ *
++ * Returns: The extended timestamp of @timestamp.
++ *
++ * Since: 0.10.15
++ */
++guint64
++gst_rtp_buffer_ext_timestamp (guint64 * exttimestamp, guint32 timestamp)
++{
++  guint64 result, diff, ext;
++
++  g_return_val_if_fail (exttimestamp != NULL, -1);
++
++  ext = *exttimestamp;
++
++  if (ext == -1) {
++    result = timestamp;
++  } else {
++    /* pick wraparound counter from previous timestamp and add to new timestamp */
++    result = timestamp + (ext & ~(G_GINT64_CONSTANT (0xffffffff)));
++
++    /* check for timestamp wraparound */
++    if (result < ext)
++      diff = ext - result;
++    else
++      diff = result - ext;
++
++    if (diff > G_MAXINT32) {
++      /* timestamp went backwards more than allowed, we wrap around and get
++       * updated extended timestamp. */
++      result += (G_GINT64_CONSTANT (1) << 32);
++    }
++  }
++  *exttimestamp = result;
++
++  return result;
++}
++
++/**
++ * gst_rtp_buffer_list_get_data:
++ * @list: a buffer list
++ *
++ * Returns ponter to the RTP header of the first packet within the list
++ *
++ * Returns: pointer to the first RTP header
++ */
++static guint8 *
++gst_rtp_buffer_list_get_data (GstBufferList * list)
++{
++  GstBufferListIterator *it;
++  GstBuffer *rtpbuf;
++
++  it = gst_buffer_list_iterate (list);
++  if (!gst_buffer_list_iterator_next_group (it))
++    goto invalid_list;
++  rtpbuf = gst_buffer_list_iterator_next (it);
++  if (!rtpbuf)
++    goto invalid_list;
++
++  gst_buffer_list_iterator_free (it);
++  return GST_BUFFER_DATA (rtpbuf);
++
++invalid_list:
++  gst_buffer_list_iterator_free (it);
++  g_return_val_if_reached (FALSE);
++}
++
++/**
++ * gst_rtp_buffer_list_set_rtp_headers:
++ * @list: a buffer list
++ * @data: data to be set
++ * @type: which field in the header to be set
++ *
++ * Sets the field specified by @type to @data.
++ * This function updates all RTP headers within @list.
++ */
++static void
++gst_rtp_buffer_list_set_rtp_headers (GstBufferList * list,
++    gpointer data, rtp_header_data_type type)
++{
++  GstBufferListIterator *it;
++  it = gst_buffer_list_iterate (list);
++
++  while (gst_buffer_list_iterator_next_group (it)) {
++    GstBuffer *rtpbuf;
++    guint8 *rtp_header;
++    rtpbuf = gst_buffer_list_iterator_next (it);
++    rtp_header = GST_BUFFER_DATA (rtpbuf);
++    gst_rtp_buffer_list_set_data (rtp_header, data, type);
++  }
++
++  gst_buffer_list_iterator_free (it);
++}
++
++/**
++ * gst_rtp_buffer_list_set_data:
++ * @rtp_header: rtp header to be updated
++ * @data: data to be set
++ * @type: which field in the header to be set
++ *
++ * Sets the field specified by @type to @data.
++ * When setting SEQ number, this function will also increase
++ * @data by one.
++ */
++static void
++gst_rtp_buffer_list_set_data (guint8 * rtp_header,
++    gpointer data, rtp_header_data_type type)
++{
++  switch (type) {
++    case PAYLOAD_TYPE:
++      GST_RTP_HEADER_PAYLOAD_TYPE (rtp_header) = *(guint8 *) data;
++      break;
++    case SEQ:
++      GST_RTP_HEADER_SEQ (rtp_header) = g_htons (*(guint16 *) data);
++      (*(guint16 *) data)++;
++      break;
++    case SSRC:
++      GST_RTP_HEADER_SSRC (rtp_header) = g_htonl (*(guint32 *) data);
++      break;
++    case TIMESTAMP:
++      GST_RTP_HEADER_TIMESTAMP (rtp_header) = g_htonl (*(guint32 *) data);
++      break;
++    default:
++      g_warning ("Unknown data type");
++      break;
++  }
++}
index 0000000,0000000..088a67e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3519 @@@
++/* GStreamer
++ * Copyright (C) <2005-2009> Wim Taymans <wim.taymans@gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++/*
++ * Unless otherwise indicated, Source Code is licensed under MIT license.
++ * See further explanation attached in License Statement (distributed in the file
++ * LICENSE).
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy of
++ * this software and associated documentation files (the "Software"), to deal in
++ * the Software without restriction, including without limitation the rights to
++ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
++ * of the Software, and to permit persons to whom the Software is furnished to do
++ * so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in all
++ * copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ */
++
++/**
++ * SECTION:gstrtspconnection
++ * @short_description: manage RTSP connections
++ * @see_also: gstrtspurl
++ *  
++ * <refsect2>
++ * <para>
++ * This object manages the RTSP connection to the server. It provides function
++ * to receive and send bytes and messages.
++ * </para>
++ * </refsect2>
++ *  
++ * Last reviewed on 2007-07-24 (0.10.14)
++ */
++
++#ifdef HAVE_CONFIG_H
++#  include <config.h>
++#endif
++
++#include <stdio.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++/* we include this here to get the G_OS_* defines */
++#include <glib.h>
++#include <gst/gst.h>
++
++#ifdef G_OS_WIN32
++/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
++ * minwg32 headers check WINVER before allowing the use of these */
++#ifndef WINVER
++#define WINVER 0x0501
++#endif
++#include <winsock2.h>
++#include <ws2tcpip.h>
++#define EINPROGRESS WSAEINPROGRESS
++#else
++#include <sys/ioctl.h>
++#include <netdb.h>
++#include <sys/socket.h>
++#include <fcntl.h>
++#include <netinet/in.h>
++#endif
++
++#ifdef HAVE_FIONREAD_IN_SYS_FILIO
++#include <sys/filio.h>
++#endif
++
++#include "gstrtspconnection.h"
++#include "gstrtspbase64.h"
++
++union gst_sockaddr
++{
++  struct sockaddr sa;
++  struct sockaddr_in sa_in;
++  struct sockaddr_in6 sa_in6;
++  struct sockaddr_storage sa_stor;
++};
++
++typedef struct
++{
++  gint state;
++  guint save;
++  guchar out[3];                /* the size must be evenly divisible by 3 */
++  guint cout;
++  guint coutl;
++} DecodeCtx;
++
++#ifdef G_OS_WIN32
++#define READ_SOCKET(fd, buf, len) recv (fd, (char *)buf, len, 0)
++#define WRITE_SOCKET(fd, buf, len) send (fd, (const char *)buf, len, 0)
++#define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, (const char *)val, len)
++#define CLOSE_SOCKET(sock) closesocket (sock)
++#define ERRNO_IS_EAGAIN (WSAGetLastError () == WSAEWOULDBLOCK)
++#define ERRNO_IS_EINTR (WSAGetLastError () == WSAEINTR)
++/* According to Microsoft's connect() documentation this one returns
++ * WSAEWOULDBLOCK and not WSAEINPROGRESS. */
++#define ERRNO_IS_EINPROGRESS (WSAGetLastError () == WSAEWOULDBLOCK)
++#else
++#define READ_SOCKET(fd, buf, len) read (fd, buf, len)
++#define WRITE_SOCKET(fd, buf, len) write (fd, buf, len)
++#define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, val, len)
++#define CLOSE_SOCKET(sock) close (sock)
++#define ERRNO_IS_EAGAIN (errno == EAGAIN)
++#define ERRNO_IS_EINTR (errno == EINTR)
++#define ERRNO_IS_EINPROGRESS (errno == EINPROGRESS)
++#endif
++
++#define ADD_POLLFD(fdset, pfd, fd)        \
++G_STMT_START {                            \
++  (pfd)->fd = fd;                         \
++  gst_poll_add_fd (fdset, pfd);           \
++} G_STMT_END
++
++#define REMOVE_POLLFD(fdset, pfd)          \
++G_STMT_START {                             \
++  if ((pfd)->fd != -1) {                   \
++    GST_DEBUG ("remove fd %d", (pfd)->fd); \
++    gst_poll_remove_fd (fdset, pfd);       \
++    CLOSE_SOCKET ((pfd)->fd);              \
++    (pfd)->fd = -1;                        \
++  }                                        \
++} G_STMT_END
++
++typedef enum
++{
++  TUNNEL_STATE_NONE,
++  TUNNEL_STATE_GET,
++  TUNNEL_STATE_POST,
++  TUNNEL_STATE_COMPLETE
++} GstRTSPTunnelState;
++
++#define TUNNELID_LEN   24
++
++struct _GstRTSPConnection
++{
++  /*< private > */
++  /* URL for the connection */
++  GstRTSPUrl *url;
++
++  /* connection state */
++  GstPollFD fd0;
++  GstPollFD fd1;
++
++  GstPollFD *readfd;
++  GstPollFD *writefd;
++
++  gboolean manual_http;
++
++  gchar tunnelid[TUNNELID_LEN];
++  gboolean tunneled;
++  GstRTSPTunnelState tstate;
++
++  GstPoll *fdset;
++  gchar *ip;
++
++  gint read_ahead;
++
++  gchar *initial_buffer;
++  gsize initial_buffer_offset;
++
++  /* Session state */
++  gint cseq;                    /* sequence number */
++  gchar session_id[512];        /* session id */
++  gint timeout;                 /* session timeout in seconds */
++  GTimer *timer;                /* timeout timer */
++
++  /* Authentication */
++  GstRTSPAuthMethod auth_method;
++  gchar *username;
++  gchar *passwd;
++  GHashTable *auth_params;
++
++  DecodeCtx ctx;
++  DecodeCtx *ctxp;
++
++  gchar *proxy_host;
++  guint proxy_port;
++};
++
++enum
++{
++  STATE_START = 0,
++  STATE_DATA_HEADER,
++  STATE_DATA_BODY,
++  STATE_READ_LINES,
++  STATE_END,
++  STATE_LAST
++};
++
++enum
++{
++  READ_AHEAD_EOH = -1,          /* end of headers */
++  READ_AHEAD_CRLF = -2,
++  READ_AHEAD_CRLFCR = -3
++};
++
++/* a structure for constructing RTSPMessages */
++typedef struct
++{
++  gint state;
++  GstRTSPResult status;
++  guint8 buffer[4096];
++  guint offset;
++
++  guint line;
++  guint8 *body_data;
++  glong body_len;
++} GstRTSPBuilder;
++
++static void
++build_reset (GstRTSPBuilder * builder)
++{
++  g_free (builder->body_data);
++  memset (builder, 0, sizeof (GstRTSPBuilder));
++}
++
++/**
++ * gst_rtsp_connection_create:
++ * @url: a #GstRTSPUrl 
++ * @conn: storage for a #GstRTSPConnection
++ *
++ * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
++ * The connection will not yet attempt to connect to @url, use
++ * gst_rtsp_connection_connect().
++ *
++ * A copy of @url will be made.
++ *
++ * Returns: #GST_RTSP_OK when @conn contains a valid connection.
++ */
++GstRTSPResult
++gst_rtsp_connection_create (const GstRTSPUrl * url, GstRTSPConnection ** conn)
++{
++  GstRTSPConnection *newconn;
++#ifdef G_OS_WIN32
++  WSADATA w;
++  int error;
++#endif
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++#ifdef G_OS_WIN32
++  error = WSAStartup (0x0202, &w);
++
++  if (error)
++    goto startup_error;
++
++  if (w.wVersion != 0x0202)
++    goto version_error;
++#endif
++
++  newconn = g_new0 (GstRTSPConnection, 1);
++
++  if ((newconn->fdset = gst_poll_new (TRUE)) == NULL)
++    goto no_fdset;
++
++  newconn->url = gst_rtsp_url_copy (url);
++  newconn->fd0.fd = -1;
++  newconn->fd1.fd = -1;
++  newconn->timer = g_timer_new ();
++  newconn->timeout = 60;
++  newconn->cseq = 1;
++
++  newconn->auth_method = GST_RTSP_AUTH_NONE;
++  newconn->username = NULL;
++  newconn->passwd = NULL;
++  newconn->auth_params = NULL;
++
++  *conn = newconn;
++
++  return GST_RTSP_OK;
++
++  /* ERRORS */
++#ifdef G_OS_WIN32
++startup_error:
++  {
++    g_warning ("Error %d on WSAStartup", error);
++    return GST_RTSP_EWSASTART;
++  }
++version_error:
++  {
++    g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
++        w.wVersion);
++    WSACleanup ();
++    return GST_RTSP_EWSAVERSION;
++  }
++#endif
++no_fdset:
++  {
++    g_free (newconn);
++#ifdef G_OS_WIN32
++    WSACleanup ();
++#endif
++    return GST_RTSP_ESYS;
++  }
++}
++
++/**
++ * gst_rtsp_connection_create_from_fd:
++ * @fd: a file descriptor
++ * @ip: the IP address of the other end
++ * @port: the port used by the other end
++ * @initial_buffer: data already read from @fd
++ * @conn: storage for a #GstRTSPConnection
++ *
++ * Create a new #GstRTSPConnection for handling communication on the existing
++ * file descriptor @fd. The @initial_buffer contains any data already read from
++ * @fd which should be used before starting to read new data.
++ *
++ * Returns: #GST_RTSP_OK when @conn contains a valid connection.
++ *
++ * Since: 0.10.25
++ */
++GstRTSPResult
++gst_rtsp_connection_create_from_fd (gint fd, const gchar * ip, guint16 port,
++    const gchar * initial_buffer, GstRTSPConnection ** conn)
++{
++  GstRTSPConnection *newconn = NULL;
++  GstRTSPUrl *url;
++#ifdef G_OS_WIN32
++  gulong flags = 1;
++#endif
++  GstRTSPResult res;
++
++  g_return_val_if_fail (fd >= 0, GST_RTSP_EINVAL);
++  g_return_val_if_fail (ip != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++  /* set to non-blocking mode so that we can cancel the communication */
++#ifndef G_OS_WIN32
++  fcntl (fd, F_SETFL, O_NONBLOCK);
++#else
++  ioctlsocket (fd, FIONBIO, &flags);
++#endif /* G_OS_WIN32 */
++
++  /* create a url for the client address */
++  url = g_new0 (GstRTSPUrl, 1);
++  url->host = g_strdup (ip);
++  url->port = port;
++
++  /* now create the connection object */
++  GST_RTSP_CHECK (gst_rtsp_connection_create (url, &newconn), newconn_failed);
++  gst_rtsp_url_free (url);
++
++  ADD_POLLFD (newconn->fdset, &newconn->fd0, fd);
++
++  /* both read and write initially */
++  newconn->readfd = &newconn->fd0;
++  newconn->writefd = &newconn->fd0;
++
++  newconn->ip = g_strdup (ip);
++
++  newconn->initial_buffer = g_strdup (initial_buffer);
++
++  *conn = newconn;
++
++  return GST_RTSP_OK;
++
++  /* ERRORS */
++newconn_failed:
++  {
++    gst_rtsp_url_free (url);
++    return res;
++  }
++}
++
++/**
++ * gst_rtsp_connection_accept:
++ * @sock: a socket
++ * @conn: storage for a #GstRTSPConnection
++ *
++ * Accept a new connection on @sock and create a new #GstRTSPConnection for
++ * handling communication on new socket.
++ *
++ * Returns: #GST_RTSP_OK when @conn contains a valid connection.
++ *
++ * Since: 0.10.23
++ */
++GstRTSPResult
++gst_rtsp_connection_accept (gint sock, GstRTSPConnection ** conn)
++{
++  int fd;
++  union gst_sockaddr sa;
++  socklen_t slen = sizeof (sa);
++  gchar ip[INET6_ADDRSTRLEN];
++  guint16 port;
++
++  g_return_val_if_fail (sock >= 0, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++  memset (&sa, 0, slen);
++
++#ifndef G_OS_WIN32
++  fd = accept (sock, &sa.sa, &slen);
++#else
++  fd = accept (sock, &sa.sa, (gint *) & slen);
++#endif /* G_OS_WIN32 */
++  if (fd == -1)
++    goto accept_failed;
++
++  if (getnameinfo (&sa.sa, slen, ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) != 0)
++    goto getnameinfo_failed;
++
++  if (sa.sa.sa_family == AF_INET)
++    port = sa.sa_in.sin_port;
++  else if (sa.sa.sa_family == AF_INET6)
++    port = sa.sa_in6.sin6_port;
++  else
++    goto wrong_family;
++
++  return gst_rtsp_connection_create_from_fd (fd, ip, port, NULL, conn);
++
++  /* ERRORS */
++accept_failed:
++  {
++    return GST_RTSP_ESYS;
++  }
++getnameinfo_failed:
++wrong_family:
++  {
++    CLOSE_SOCKET (fd);
++    return GST_RTSP_ERROR;
++  }
++}
++
++static gchar *
++do_resolve (const gchar * host)
++{
++  static gchar ip[INET6_ADDRSTRLEN];
++  struct addrinfo *aires;
++  struct addrinfo *ai;
++  gint aierr;
++
++  aierr = getaddrinfo (host, NULL, NULL, &aires);
++  if (aierr != 0)
++    goto no_addrinfo;
++
++  for (ai = aires; ai; ai = ai->ai_next) {
++    if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
++      break;
++    }
++  }
++  if (ai == NULL)
++    goto no_family;
++
++  aierr = getnameinfo (ai->ai_addr, ai->ai_addrlen, ip, sizeof (ip), NULL, 0,
++      NI_NUMERICHOST | NI_NUMERICSERV);
++  if (aierr != 0)
++    goto no_address;
++
++  freeaddrinfo (aires);
++
++  return g_strdup (ip);
++
++  /* ERRORS */
++no_addrinfo:
++  {
++    GST_ERROR ("no addrinfo found for %s: %s", host, gai_strerror (aierr));
++    return NULL;
++  }
++no_family:
++  {
++    GST_ERROR ("no family found for %s", host);
++    freeaddrinfo (aires);
++    return NULL;
++  }
++no_address:
++  {
++    GST_ERROR ("no address found for %s: %s", host, gai_strerror (aierr));
++    freeaddrinfo (aires);
++    return NULL;
++  }
++}
++
++static GstRTSPResult
++do_connect (const gchar * ip, guint16 port, GstPollFD * fdout,
++    GstPoll * fdset, GTimeVal * timeout)
++{
++  gint fd;
++  struct addrinfo hints;
++  struct addrinfo *aires;
++  struct addrinfo *ai;
++  gint aierr;
++  gchar service[NI_MAXSERV];
++  gint ret;
++#ifdef G_OS_WIN32
++  unsigned long flags = 1;
++#endif /* G_OS_WIN32 */
++  GstClockTime to;
++  gint retval;
++
++  memset (&hints, 0, sizeof hints);
++  hints.ai_flags = AI_NUMERICHOST;
++  hints.ai_family = AF_UNSPEC;
++  hints.ai_socktype = SOCK_STREAM;
++  g_snprintf (service, sizeof (service) - 1, "%hu", port);
++  service[sizeof (service) - 1] = '\0';
++
++  aierr = getaddrinfo (ip, service, &hints, &aires);
++  if (aierr != 0)
++    goto no_addrinfo;
++
++  for (ai = aires; ai; ai = ai->ai_next) {
++    if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
++      break;
++    }
++  }
++  if (ai == NULL)
++    goto no_family;
++
++  fd = socket (ai->ai_family, SOCK_STREAM, 0);
++  if (fd == -1)
++    goto no_socket;
++
++  /* set to non-blocking mode so that we can cancel the connect */
++#ifndef G_OS_WIN32
++  fcntl (fd, F_SETFL, O_NONBLOCK);
++#else
++  ioctlsocket (fd, FIONBIO, &flags);
++#endif /* G_OS_WIN32 */
++
++  /* add the socket to our fdset */
++  ADD_POLLFD (fdset, fdout, fd);
++
++  /* we are going to connect ASYNC now */
++  ret = connect (fd, ai->ai_addr, ai->ai_addrlen);
++  if (ret == 0)
++    goto done;
++  if (!ERRNO_IS_EINPROGRESS)
++    goto sys_error;
++
++  /* wait for connect to complete up to the specified timeout or until we got
++   * interrupted. */
++  gst_poll_fd_ctl_write (fdset, fdout, TRUE);
++
++  to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
++
++  do {
++    retval = gst_poll_wait (fdset, to);
++  } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
++
++  if (retval == 0)
++    goto timeout;
++  else if (retval == -1)
++    goto sys_error;
++
++  /* we can still have an error connecting on windows */
++  if (gst_poll_fd_has_error (fdset, fdout)) {
++    socklen_t len = sizeof (errno);
++#ifndef G_OS_WIN32
++    getsockopt (fd, SOL_SOCKET, SO_ERROR, &errno, &len);
++#else
++    getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno, &len);
++#endif
++    goto sys_error;
++  }
++
++  gst_poll_fd_ignored (fdset, fdout);
++
++done:
++  freeaddrinfo (aires);
++
++  return GST_RTSP_OK;
++
++  /* ERRORS */
++no_addrinfo:
++  {
++    GST_ERROR ("no addrinfo found for %s: %s", ip, gai_strerror (aierr));
++    return GST_RTSP_ERROR;
++  }
++no_family:
++  {
++    GST_ERROR ("no family found for %s", ip);
++    freeaddrinfo (aires);
++    return GST_RTSP_ERROR;
++  }
++no_socket:
++  {
++    GST_ERROR ("no socket %d (%s)", errno, g_strerror (errno));
++    freeaddrinfo (aires);
++    return GST_RTSP_ESYS;
++  }
++sys_error:
++  {
++    GST_ERROR ("system error %d (%s)", errno, g_strerror (errno));
++    REMOVE_POLLFD (fdset, fdout);
++    freeaddrinfo (aires);
++    return GST_RTSP_ESYS;
++  }
++timeout:
++  {
++    GST_ERROR ("timeout");
++    REMOVE_POLLFD (fdset, fdout);
++    freeaddrinfo (aires);
++    return GST_RTSP_ETIMEOUT;
++  }
++}
++
++static GstRTSPResult
++setup_tunneling (GstRTSPConnection * conn, GTimeVal * timeout)
++{
++  gint i;
++  GstRTSPResult res;
++  gchar *ip;
++  gchar *uri;
++  gchar *value;
++  guint16 port, url_port;
++  GstRTSPUrl *url;
++  gchar *hostparam;
++  GstRTSPMessage *msg;
++  GstRTSPMessage response;
++  gboolean old_http;
++
++  memset (&response, 0, sizeof (response));
++  gst_rtsp_message_init (&response);
++
++  /* create a random sessionid */
++  for (i = 0; i < TUNNELID_LEN; i++)
++    conn->tunnelid[i] = g_random_int_range ('a', 'z');
++  conn->tunnelid[TUNNELID_LEN - 1] = '\0';
++
++  url = conn->url;
++  /* get the port from the url */
++  gst_rtsp_url_get_port (url, &url_port);
++
++  if (conn->proxy_host) {
++    uri = g_strdup_printf ("http://%s:%d%s%s%s", url->host, url_port,
++        url->abspath, url->query ? "?" : "", url->query ? url->query : "");
++    hostparam = g_strdup_printf ("%s:%d", url->host, url_port);
++    ip = conn->proxy_host;
++    port = conn->proxy_port;
++  } else {
++    uri = g_strdup_printf ("%s%s%s", url->abspath, url->query ? "?" : "",
++        url->query ? url->query : "");
++    hostparam = NULL;
++    ip = conn->ip;
++    port = url_port;
++  }
++
++  /* create the GET request for the read connection */
++  GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_GET, uri),
++      no_message);
++  msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
++
++  if (hostparam != NULL)
++    gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, hostparam);
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
++      conn->tunnelid);
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
++      "application/x-rtsp-tunnelled");
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
++
++  /* we start by writing to this fd */
++  conn->writefd = &conn->fd0;
++
++  /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
++   * request from being base64 encoded */
++  conn->tunneled = FALSE;
++  GST_RTSP_CHECK (gst_rtsp_connection_send (conn, msg, timeout), write_failed);
++  gst_rtsp_message_free (msg);
++  conn->tunneled = TRUE;
++
++  /* receive the response to the GET request */
++  /* we need to temporarily set manual_http to TRUE since
++   * gst_rtsp_connection_receive() will treat the HTTP response as a parsing
++   * failure otherwise */
++  old_http = conn->manual_http;
++  conn->manual_http = TRUE;
++  GST_RTSP_CHECK (gst_rtsp_connection_receive (conn, &response, timeout),
++      read_failed);
++  conn->manual_http = old_http;
++
++  if (response.type != GST_RTSP_MESSAGE_HTTP_RESPONSE ||
++      response.type_data.response.code != GST_RTSP_STS_OK)
++    goto wrong_result;
++
++  if (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
++          &value, 0) != GST_RTSP_OK) {
++    if (conn->proxy_host) {
++      /* if we use a proxy we need to change the destination url */
++      g_free (url->host);
++      url->host = g_strdup (value);
++      g_free (hostparam);
++      hostparam = g_strdup_printf ("%s:%d", url->host, url_port);
++    } else {
++      /* and resolve the new ip address */
++      if (!(ip = do_resolve (conn->ip)))
++        goto not_resolved;
++      g_free (conn->ip);
++      conn->ip = ip;
++    }
++  }
++
++  /* connect to the host/port */
++  res = do_connect (ip, port, &conn->fd1, conn->fdset, timeout);
++  if (res != GST_RTSP_OK)
++    goto connect_failed;
++
++  /* this is now our writing socket */
++  conn->writefd = &conn->fd1;
++
++  /* create the POST request for the write connection */
++  GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_POST, uri),
++      no_message);
++  msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
++
++  if (hostparam != NULL)
++    gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, hostparam);
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
++      conn->tunnelid);
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
++      "application/x-rtsp-tunnelled");
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_EXPIRES,
++      "Sun, 9 Jan 1972 00:00:00 GMT");
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH, "32767");
++
++  /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
++   * request from being base64 encoded */
++  conn->tunneled = FALSE;
++  GST_RTSP_CHECK (gst_rtsp_connection_send (conn, msg, timeout), write_failed);
++  gst_rtsp_message_free (msg);
++  conn->tunneled = TRUE;
++
++exit:
++  gst_rtsp_message_unset (&response);
++  g_free (hostparam);
++  g_free (uri);
++
++  return res;
++
++  /* ERRORS */
++no_message:
++  {
++    GST_ERROR ("failed to create request (%d)", res);
++    goto exit;
++  }
++write_failed:
++  {
++    GST_ERROR ("write failed (%d)", res);
++    gst_rtsp_message_free (msg);
++    conn->tunneled = TRUE;
++    goto exit;
++  }
++read_failed:
++  {
++    GST_ERROR ("read failed (%d)", res);
++    conn->manual_http = FALSE;
++    goto exit;
++  }
++wrong_result:
++  {
++    GST_ERROR ("got failure response %d %s", response.type_data.response.code,
++        response.type_data.response.reason);
++    res = GST_RTSP_ERROR;
++    goto exit;
++  }
++not_resolved:
++  {
++    GST_ERROR ("could not resolve %s", conn->ip);
++    res = GST_RTSP_ENET;
++    goto exit;
++  }
++connect_failed:
++  {
++    GST_ERROR ("failed to connect");
++    goto exit;
++  }
++}
++
++/**
++ * gst_rtsp_connection_connect:
++ * @conn: a #GstRTSPConnection 
++ * @timeout: a #GTimeVal timeout
++ *
++ * Attempt to connect to the url of @conn made with
++ * gst_rtsp_connection_create(). If @timeout is #NULL this function can block
++ * forever. If @timeout contains a valid timeout, this function will return
++ * #GST_RTSP_ETIMEOUT after the timeout expired.
++ *
++ * This function can be cancelled with gst_rtsp_connection_flush().
++ *
++ * Returns: #GST_RTSP_OK when a connection could be made.
++ */
++GstRTSPResult
++gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
++{
++  GstRTSPResult res;
++  gchar *ip;
++  guint16 port;
++  GstRTSPUrl *url;
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn->fd0.fd < 0, GST_RTSP_EINVAL);
++
++  url = conn->url;
++
++  if (conn->proxy_host && conn->tunneled) {
++    if (!(ip = do_resolve (conn->proxy_host))) {
++      GST_ERROR ("could not resolve %s", conn->proxy_host);
++      goto not_resolved;
++    }
++    port = conn->proxy_port;
++    g_free (conn->proxy_host);
++    conn->proxy_host = ip;
++  } else {
++    if (!(ip = do_resolve (url->host))) {
++      GST_ERROR ("could not resolve %s", url->host);
++      goto not_resolved;
++    }
++    /* get the port from the url */
++    gst_rtsp_url_get_port (url, &port);
++
++    g_free (conn->ip);
++    conn->ip = ip;
++  }
++
++  /* connect to the host/port */
++  res = do_connect (ip, port, &conn->fd0, conn->fdset, timeout);
++  if (res != GST_RTSP_OK)
++    goto connect_failed;
++
++  /* this is our read URL */
++  conn->readfd = &conn->fd0;
++
++  if (conn->tunneled) {
++    res = setup_tunneling (conn, timeout);
++    if (res != GST_RTSP_OK)
++      goto tunneling_failed;
++  } else {
++    conn->writefd = &conn->fd0;
++  }
++
++  return GST_RTSP_OK;
++
++not_resolved:
++  {
++    return GST_RTSP_ENET;
++  }
++connect_failed:
++  {
++    GST_ERROR ("failed to connect");
++    return res;
++  }
++tunneling_failed:
++  {
++    GST_ERROR ("failed to setup tunneling");
++    return res;
++  }
++}
++
++static void
++auth_digest_compute_hex_urp (const gchar * username,
++    const gchar * realm, const gchar * password, gchar hex_urp[33])
++{
++  GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5);
++  const gchar *digest_string;
++
++  g_checksum_update (md5_context, (const guchar *) username, strlen (username));
++  g_checksum_update (md5_context, (const guchar *) ":", 1);
++  g_checksum_update (md5_context, (const guchar *) realm, strlen (realm));
++  g_checksum_update (md5_context, (const guchar *) ":", 1);
++  g_checksum_update (md5_context, (const guchar *) password, strlen (password));
++  digest_string = g_checksum_get_string (md5_context);
++
++  memset (hex_urp, 0, 33);
++  memcpy (hex_urp, digest_string, strlen (digest_string));
++
++  g_checksum_free (md5_context);
++}
++
++static void
++auth_digest_compute_response (const gchar * method,
++    const gchar * uri, const gchar * hex_a1, const gchar * nonce,
++    gchar response[33])
++{
++  char hex_a2[33] = { 0, };
++  GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5);
++  const gchar *digest_string;
++
++  /* compute A2 */
++  g_checksum_update (md5_context, (const guchar *) method, strlen (method));
++  g_checksum_update (md5_context, (const guchar *) ":", 1);
++  g_checksum_update (md5_context, (const guchar *) uri, strlen (uri));
++  digest_string = g_checksum_get_string (md5_context);
++  memcpy (hex_a2, digest_string, strlen (digest_string));
++
++  /* compute KD */
++  g_checksum_reset (md5_context);
++  g_checksum_update (md5_context, (const guchar *) hex_a1, strlen (hex_a1));
++  g_checksum_update (md5_context, (const guchar *) ":", 1);
++  g_checksum_update (md5_context, (const guchar *) nonce, strlen (nonce));
++  g_checksum_update (md5_context, (const guchar *) ":", 1);
++
++  g_checksum_update (md5_context, (const guchar *) hex_a2, 32);
++  digest_string = g_checksum_get_string (md5_context);
++  memset (response, 0, 33);
++  memcpy (response, digest_string, strlen (digest_string));
++
++  g_checksum_free (md5_context);
++}
++
++static void
++add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
++{
++  switch (conn->auth_method) {
++    case GST_RTSP_AUTH_BASIC:{
++      gchar *user_pass;
++      gchar *user_pass64;
++      gchar *auth_string;
++
++      user_pass = g_strdup_printf ("%s:%s", conn->username, conn->passwd);
++      user_pass64 = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
++      auth_string = g_strdup_printf ("Basic %s", user_pass64);
++
++      gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
++          auth_string);
++
++      g_free (user_pass);
++      g_free (user_pass64);
++      break;
++    }
++    case GST_RTSP_AUTH_DIGEST:{
++      gchar response[33], hex_urp[33];
++      gchar *auth_string, *auth_string2;
++      gchar *realm;
++      gchar *nonce;
++      gchar *opaque;
++      const gchar *uri;
++      const gchar *method;
++
++      /* we need to have some params set */
++      if (conn->auth_params == NULL)
++        break;
++
++      /* we need the realm and nonce */
++      realm = (gchar *) g_hash_table_lookup (conn->auth_params, "realm");
++      nonce = (gchar *) g_hash_table_lookup (conn->auth_params, "nonce");
++      if (realm == NULL || nonce == NULL)
++        break;
++
++      auth_digest_compute_hex_urp (conn->username, realm, conn->passwd,
++          hex_urp);
++
++      method = gst_rtsp_method_as_text (message->type_data.request.method);
++      uri = message->type_data.request.uri;
++
++      /* Assume no qop, algorithm=md5, stale=false */
++      /* For algorithm MD5, a1 = urp. */
++      auth_digest_compute_response (method, uri, hex_urp, nonce, response);
++      auth_string = g_strdup_printf ("Digest username=\"%s\", "
++          "realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
++          conn->username, realm, nonce, uri, response);
++
++      opaque = (gchar *) g_hash_table_lookup (conn->auth_params, "opaque");
++      if (opaque) {
++        auth_string2 = g_strdup_printf ("%s, opaque=\"%s\"", auth_string,
++            opaque);
++        g_free (auth_string);
++        auth_string = auth_string2;
++      }
++      gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
++          auth_string);
++      break;
++    }
++    default:
++      /* Nothing to do */
++      break;
++  }
++}
++
++static void
++gen_date_string (gchar * date_string, guint len)
++{
++  GTimeVal tv;
++  time_t t;
++#ifdef HAVE_GMTIME_R
++  struct tm tm_;
++#endif
++
++  g_get_current_time (&tv);
++  t = (time_t) tv.tv_sec;
++
++#ifdef HAVE_GMTIME_R
++  strftime (date_string, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime_r (&t, &tm_));
++#else
++  strftime (date_string, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime (&t));
++#endif
++}
++
++static GstRTSPResult
++write_bytes (gint fd, const guint8 * buffer, guint * idx, guint size)
++{
++  guint left;
++
++  if (G_UNLIKELY (*idx > size))
++    return GST_RTSP_ERROR;
++
++  left = size - *idx;
++
++  while (left) {
++    gint r;
++
++    r = WRITE_SOCKET (fd, &buffer[*idx], left);
++    if (G_UNLIKELY (r == 0)) {
++      return GST_RTSP_EINTR;
++    } else if (G_UNLIKELY (r < 0)) {
++      if (ERRNO_IS_EAGAIN)
++        return GST_RTSP_EINTR;
++      if (!ERRNO_IS_EINTR)
++        return GST_RTSP_ESYS;
++    } else {
++      left -= r;
++      *idx += r;
++    }
++  }
++  return GST_RTSP_OK;
++}
++
++static gint
++fill_raw_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size)
++{
++  gint out = 0;
++
++  if (G_UNLIKELY (conn->initial_buffer != NULL)) {
++    gsize left = strlen (&conn->initial_buffer[conn->initial_buffer_offset]);
++
++    out = MIN (left, size);
++    memcpy (buffer, &conn->initial_buffer[conn->initial_buffer_offset], out);
++
++    if (left == (gsize) out) {
++      g_free (conn->initial_buffer);
++      conn->initial_buffer = NULL;
++      conn->initial_buffer_offset = 0;
++    } else
++      conn->initial_buffer_offset += out;
++  }
++
++  if (G_LIKELY (size > (guint) out)) {
++    gint r;
++
++    r = READ_SOCKET (conn->readfd->fd, &buffer[out], size - out);
++    if (r <= 0) {
++      if (out == 0)
++        out = r;
++    } else
++      out += r;
++  }
++
++  return out;
++}
++
++static gint
++fill_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size)
++{
++  DecodeCtx *ctx = conn->ctxp;
++  gint out = 0;
++
++  if (ctx) {
++    while (size > 0) {
++      guint8 in[sizeof (ctx->out) * 4 / 3];
++      gint r;
++
++      while (size > 0 && ctx->cout < ctx->coutl) {
++        /* we have some leftover bytes */
++        *buffer++ = ctx->out[ctx->cout++];
++        size--;
++        out++;
++      }
++
++      /* got what we needed? */
++      if (size == 0)
++        break;
++
++      /* try to read more bytes */
++      r = fill_raw_bytes (conn, in, sizeof (in));
++      if (r <= 0) {
++        if (out == 0)
++          out = r;
++        break;
++      }
++
++      ctx->cout = 0;
++      ctx->coutl =
++          g_base64_decode_step ((gchar *) in, r, ctx->out, &ctx->state,
++          &ctx->save);
++    }
++  } else {
++    out = fill_raw_bytes (conn, buffer, size);
++  }
++
++  return out;
++}
++
++static GstRTSPResult
++read_bytes (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size)
++{
++  guint left;
++
++  if (G_UNLIKELY (*idx > size))
++    return GST_RTSP_ERROR;
++
++  left = size - *idx;
++
++  while (left) {
++    gint r;
++
++    r = fill_bytes (conn, &buffer[*idx], left);
++    if (G_UNLIKELY (r == 0)) {
++      return GST_RTSP_EEOF;
++    } else if (G_UNLIKELY (r < 0)) {
++      if (ERRNO_IS_EAGAIN)
++        return GST_RTSP_EINTR;
++      if (!ERRNO_IS_EINTR)
++        return GST_RTSP_ESYS;
++    } else {
++      left -= r;
++      *idx += r;
++    }
++  }
++  return GST_RTSP_OK;
++}
++
++/* The code below tries to handle clients using \r, \n or \r\n to indicate the
++ * end of a line. It even does its best to handle clients which mix them (even
++ * though this is a really stupid idea (tm).) It also handles Line White Space
++ * (LWS), where a line end followed by whitespace is considered LWS. This is
++ * the method used in RTSP (and HTTP) to break long lines.
++ */
++static GstRTSPResult
++read_line (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size)
++{
++  while (TRUE) {
++    guint8 c;
++    gint r;
++
++    if (conn->read_ahead == READ_AHEAD_EOH) {
++      /* the last call to read_line() already determined that we have reached
++       * the end of the headers, so convey that information now */
++      conn->read_ahead = 0;
++      break;
++    } else if (conn->read_ahead == READ_AHEAD_CRLF) {
++      /* the last call to read_line() left off after having read \r\n */
++      c = '\n';
++    } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
++      /* the last call to read_line() left off after having read \r\n\r */
++      c = '\r';
++    } else if (conn->read_ahead != 0) {
++      /* the last call to read_line() left us with a character to start with */
++      c = (guint8) conn->read_ahead;
++      conn->read_ahead = 0;
++    } else {
++      /* read the next character */
++      r = fill_bytes (conn, &c, 1);
++      if (G_UNLIKELY (r == 0)) {
++        return GST_RTSP_EEOF;
++      } else if (G_UNLIKELY (r < 0)) {
++        if (ERRNO_IS_EAGAIN)
++          return GST_RTSP_EINTR;
++        if (!ERRNO_IS_EINTR)
++          return GST_RTSP_ESYS;
++        continue;
++      }
++    }
++
++    /* special treatment of line endings */
++    if (c == '\r' || c == '\n') {
++      guint8 read_ahead;
++
++    retry:
++      /* need to read ahead one more character to know what to do... */
++      r = fill_bytes (conn, &read_ahead, 1);
++      if (G_UNLIKELY (r == 0)) {
++        return GST_RTSP_EEOF;
++      } else if (G_UNLIKELY (r < 0)) {
++        if (ERRNO_IS_EAGAIN) {
++          /* remember the original character we read and try again next time */
++          if (conn->read_ahead == 0)
++            conn->read_ahead = c;
++          return GST_RTSP_EINTR;
++        }
++        if (!ERRNO_IS_EINTR)
++          return GST_RTSP_ESYS;
++        goto retry;
++      }
++
++      if (read_ahead == ' ' || read_ahead == '\t') {
++        if (conn->read_ahead == READ_AHEAD_CRLFCR) {
++          /* got \r\n\r followed by whitespace, treat it as a normal line
++           * followed by one starting with LWS */
++          conn->read_ahead = read_ahead;
++          break;
++        } else {
++          /* got LWS, change the line ending to a space and continue */
++          c = ' ';
++          conn->read_ahead = read_ahead;
++        }
++      } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
++        if (read_ahead == '\r' || read_ahead == '\n') {
++          /* got \r\n\r\r or \r\n\r\n, treat it as the end of the headers */
++          conn->read_ahead = READ_AHEAD_EOH;
++          break;
++        } else {
++          /* got \r\n\r followed by something else, this is not really
++           * supported since we have probably just eaten the first character
++           * of the body or the next message, so just ignore the second \r
++           * and live with it... */
++          conn->read_ahead = read_ahead;
++          break;
++        }
++      } else if (conn->read_ahead == READ_AHEAD_CRLF) {
++        if (read_ahead == '\r') {
++          /* got \r\n\r so far, need one more character... */
++          conn->read_ahead = READ_AHEAD_CRLFCR;
++          goto retry;
++        } else if (read_ahead == '\n') {
++          /* got \r\n\n, treat it as the end of the headers */
++          conn->read_ahead = READ_AHEAD_EOH;
++          break;
++        } else {
++          /* found the end of a line, keep read_ahead for the next line */
++          conn->read_ahead = read_ahead;
++          break;
++        }
++      } else if (c == read_ahead) {
++        /* got double \r or \n, treat it as the end of the headers */
++        conn->read_ahead = READ_AHEAD_EOH;
++        break;
++      } else if (c == '\r' && read_ahead == '\n') {
++        /* got \r\n so far, still need more to know what to do... */
++        conn->read_ahead = READ_AHEAD_CRLF;
++        goto retry;
++      } else {
++        /* found the end of a line, keep read_ahead for the next line */
++        conn->read_ahead = read_ahead;
++        break;
++      }
++    }
++
++    if (G_LIKELY (*idx < size - 1))
++      buffer[(*idx)++] = c;
++  }
++  buffer[*idx] = '\0';
++
++  return GST_RTSP_OK;
++}
++
++/**
++ * gst_rtsp_connection_write:
++ * @conn: a #GstRTSPConnection
++ * @data: the data to write
++ * @size: the size of @data
++ * @timeout: a timeout value or #NULL
++ *
++ * Attempt to write @size bytes of @data to the connected @conn, blocking up to
++ * the specified @timeout. @timeout can be #NULL, in which case this function
++ * might block forever.
++ * 
++ * This function can be cancelled with gst_rtsp_connection_flush().
++ *
++ * Returns: #GST_RTSP_OK on success.
++ */
++GstRTSPResult
++gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
++    guint size, GTimeVal * timeout)
++{
++  guint offset;
++  gint retval;
++  GstClockTime to;
++  GstRTSPResult res;
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL);
++
++  gst_poll_set_controllable (conn->fdset, TRUE);
++  gst_poll_fd_ctl_write (conn->fdset, conn->writefd, TRUE);
++  gst_poll_fd_ctl_read (conn->fdset, conn->readfd, FALSE);
++  /* clear all previous poll results */
++  gst_poll_fd_ignored (conn->fdset, conn->writefd);
++  gst_poll_fd_ignored (conn->fdset, conn->readfd);
++
++  to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
++
++  offset = 0;
++
++  while (TRUE) {
++    /* try to write */
++    res = write_bytes (conn->writefd->fd, data, &offset, size);
++    if (G_LIKELY (res == GST_RTSP_OK))
++      break;
++    if (G_UNLIKELY (res != GST_RTSP_EINTR))
++      goto write_error;
++
++    /* not all is written, wait until we can write more */
++    do {
++      retval = gst_poll_wait (conn->fdset, to);
++    } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
++
++    if (G_UNLIKELY (retval == 0))
++      goto timeout;
++
++    if (G_UNLIKELY (retval == -1)) {
++      if (errno == EBUSY)
++        goto stopped;
++      else
++        goto select_error;
++    }
++  }
++  return GST_RTSP_OK;
++
++  /* ERRORS */
++timeout:
++  {
++    return GST_RTSP_ETIMEOUT;
++  }
++select_error:
++  {
++    return GST_RTSP_ESYS;
++  }
++stopped:
++  {
++    return GST_RTSP_EINTR;
++  }
++write_error:
++  {
++    return res;
++  }
++}
++
++static GString *
++message_to_string (GstRTSPConnection * conn, GstRTSPMessage * message)
++{
++  GString *str = NULL;
++
++  str = g_string_new ("");
++
++  switch (message->type) {
++    case GST_RTSP_MESSAGE_REQUEST:
++      /* create request string, add CSeq */
++      g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
++          "CSeq: %d\r\n",
++          gst_rtsp_method_as_text (message->type_data.request.method),
++          message->type_data.request.uri, conn->cseq++);
++      /* add session id if we have one */
++      if (conn->session_id[0] != '\0') {
++        gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1);
++        gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
++            conn->session_id);
++      }
++      /* add any authentication headers */
++      add_auth_header (conn, message);
++      break;
++    case GST_RTSP_MESSAGE_RESPONSE:
++      /* create response string */
++      g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
++          message->type_data.response.code, message->type_data.response.reason);
++      break;
++    case GST_RTSP_MESSAGE_HTTP_REQUEST:
++      /* create request string */
++      g_string_append_printf (str, "%s %s HTTP/%s\r\n",
++          gst_rtsp_method_as_text (message->type_data.request.method),
++          message->type_data.request.uri,
++          gst_rtsp_version_as_text (message->type_data.request.version));
++      /* add any authentication headers */
++      add_auth_header (conn, message);
++      break;
++    case GST_RTSP_MESSAGE_HTTP_RESPONSE:
++      /* create response string */
++      g_string_append_printf (str, "HTTP/%s %d %s\r\n",
++          gst_rtsp_version_as_text (message->type_data.request.version),
++          message->type_data.response.code, message->type_data.response.reason);
++      break;
++    case GST_RTSP_MESSAGE_DATA:
++    {
++      guint8 data_header[4];
++
++      /* prepare data header */
++      data_header[0] = '$';
++      data_header[1] = message->type_data.data.channel;
++      data_header[2] = (message->body_size >> 8) & 0xff;
++      data_header[3] = message->body_size & 0xff;
++
++      /* create string with header and data */
++      str = g_string_append_len (str, (gchar *) data_header, 4);
++      str =
++          g_string_append_len (str, (gchar *) message->body,
++          message->body_size);
++      break;
++    }
++    default:
++      g_string_free (str, TRUE);
++      g_return_val_if_reached (NULL);
++      break;
++  }
++
++  /* append headers and body */
++  if (message->type != GST_RTSP_MESSAGE_DATA) {
++    gchar date_string[100];
++
++    gen_date_string (date_string, sizeof (date_string));
++
++    /* add date header */
++    gst_rtsp_message_remove_header (message, GST_RTSP_HDR_DATE, -1);
++    gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
++
++    /* append headers */
++    gst_rtsp_message_append_headers (message, str);
++
++    /* append Content-Length and body if needed */
++    if (message->body != NULL && message->body_size > 0) {
++      gchar *len;
++
++      len = g_strdup_printf ("%d", message->body_size);
++      g_string_append_printf (str, "%s: %s\r\n",
++          gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
++      g_free (len);
++      /* header ends here */
++      g_string_append (str, "\r\n");
++      str =
++          g_string_append_len (str, (gchar *) message->body,
++          message->body_size);
++    } else {
++      /* just end headers */
++      g_string_append (str, "\r\n");
++    }
++  }
++
++  return str;
++}
++
++/**
++ * gst_rtsp_connection_send:
++ * @conn: a #GstRTSPConnection
++ * @message: the message to send
++ * @timeout: a timeout value or #NULL
++ *
++ * Attempt to send @message to the connected @conn, blocking up to
++ * the specified @timeout. @timeout can be #NULL, in which case this function
++ * might block forever.
++ * 
++ * This function can be cancelled with gst_rtsp_connection_flush().
++ *
++ * Returns: #GST_RTSP_OK on success.
++ */
++GstRTSPResult
++gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
++    GTimeVal * timeout)
++{
++  GString *string = NULL;
++  GstRTSPResult res;
++  gchar *str;
++  gsize len;
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
++
++  if (G_UNLIKELY (!(string = message_to_string (conn, message))))
++    goto no_message;
++
++  if (conn->tunneled) {
++    str = g_base64_encode ((const guchar *) string->str, string->len);
++    g_string_free (string, TRUE);
++    len = strlen (str);
++  } else {
++    str = string->str;
++    len = string->len;
++    g_string_free (string, FALSE);
++  }
++
++  /* write request */
++  res = gst_rtsp_connection_write (conn, (guint8 *) str, len, timeout);
++
++  g_free (str);
++
++  return res;
++
++no_message:
++  {
++    g_warning ("Wrong message");
++    return GST_RTSP_EINVAL;
++  }
++}
++
++static GstRTSPResult
++parse_string (gchar * dest, gint size, gchar ** src)
++{
++  GstRTSPResult res = GST_RTSP_OK;
++  gint idx;
++
++  idx = 0;
++  /* skip spaces */
++  while (g_ascii_isspace (**src))
++    (*src)++;
++
++  while (!g_ascii_isspace (**src) && **src != '\0') {
++    if (idx < size - 1)
++      dest[idx++] = **src;
++    else
++      res = GST_RTSP_EPARSE;
++    (*src)++;
++  }
++  if (size > 0)
++    dest[idx] = '\0';
++
++  return res;
++}
++
++static GstRTSPResult
++parse_protocol_version (gchar * protocol, GstRTSPMsgType * type,
++    GstRTSPVersion * version)
++{
++  GstRTSPResult res = GST_RTSP_OK;
++  gchar *ver;
++
++  if (G_LIKELY ((ver = strchr (protocol, '/')) != NULL)) {
++    guint major;
++    guint minor;
++    gchar dummychar;
++
++    *ver++ = '\0';
++
++    /* the version number must be formatted as X.Y with nothing following */
++    if (sscanf (ver, "%u.%u%c", &major, &minor, &dummychar) != 2)
++      res = GST_RTSP_EPARSE;
++
++    if (g_ascii_strcasecmp (protocol, "RTSP") == 0) {
++      if (major != 1 || minor != 0) {
++        *version = GST_RTSP_VERSION_INVALID;
++        res = GST_RTSP_ERROR;
++      }
++    } else if (g_ascii_strcasecmp (protocol, "HTTP") == 0) {
++      if (*type == GST_RTSP_MESSAGE_REQUEST)
++        *type = GST_RTSP_MESSAGE_HTTP_REQUEST;
++      else if (*type == GST_RTSP_MESSAGE_RESPONSE)
++        *type = GST_RTSP_MESSAGE_HTTP_RESPONSE;
++
++      if (major == 1 && minor == 1) {
++        *version = GST_RTSP_VERSION_1_1;
++      } else if (major != 1 || minor != 0) {
++        *version = GST_RTSP_VERSION_INVALID;
++        res = GST_RTSP_ERROR;
++      }
++    } else
++      res = GST_RTSP_EPARSE;
++  } else
++    res = GST_RTSP_EPARSE;
++
++  return res;
++}
++
++static GstRTSPResult
++parse_response_status (guint8 * buffer, GstRTSPMessage * msg)
++{
++  GstRTSPResult res = GST_RTSP_OK;
++  GstRTSPResult res2;
++  gchar versionstr[20];
++  gchar codestr[4];
++  gint code;
++  gchar *bptr;
++
++  bptr = (gchar *) buffer;
++
++  if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
++    res = GST_RTSP_EPARSE;
++
++  if (parse_string (codestr, sizeof (codestr), &bptr) != GST_RTSP_OK)
++    res = GST_RTSP_EPARSE;
++  code = atoi (codestr);
++  if (G_UNLIKELY (*codestr == '\0' || code < 0 || code >= 600))
++    res = GST_RTSP_EPARSE;
++
++  while (g_ascii_isspace (*bptr))
++    bptr++;
++
++  if (G_UNLIKELY (gst_rtsp_message_init_response (msg, code, bptr,
++              NULL) != GST_RTSP_OK))
++    res = GST_RTSP_EPARSE;
++
++  res2 = parse_protocol_version (versionstr, &msg->type,
++      &msg->type_data.response.version);
++  if (G_LIKELY (res == GST_RTSP_OK))
++    res = res2;
++
++  return res;
++}
++
++static GstRTSPResult
++parse_request_line (guint8 * buffer, GstRTSPMessage * msg)
++{
++  GstRTSPResult res = GST_RTSP_OK;
++  GstRTSPResult res2;
++  gchar versionstr[20];
++  gchar methodstr[20];
++  gchar urlstr[4096];
++  gchar *bptr;
++  GstRTSPMethod method;
++
++  bptr = (gchar *) buffer;
++
++  if (parse_string (methodstr, sizeof (methodstr), &bptr) != GST_RTSP_OK)
++    res = GST_RTSP_EPARSE;
++  method = gst_rtsp_find_method (methodstr);
++
++  if (parse_string (urlstr, sizeof (urlstr), &bptr) != GST_RTSP_OK)
++    res = GST_RTSP_EPARSE;
++  if (G_UNLIKELY (*urlstr == '\0'))
++    res = GST_RTSP_EPARSE;
++
++  if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
++    res = GST_RTSP_EPARSE;
++
++  if (G_UNLIKELY (*bptr != '\0'))
++    res = GST_RTSP_EPARSE;
++
++  if (G_UNLIKELY (gst_rtsp_message_init_request (msg, method,
++              urlstr) != GST_RTSP_OK))
++    res = GST_RTSP_EPARSE;
++
++  res2 = parse_protocol_version (versionstr, &msg->type,
++      &msg->type_data.request.version);
++  if (G_LIKELY (res == GST_RTSP_OK))
++    res = res2;
++
++  if (G_LIKELY (msg->type == GST_RTSP_MESSAGE_REQUEST)) {
++    /* GET and POST are not allowed as RTSP methods */
++    if (msg->type_data.request.method == GST_RTSP_GET ||
++        msg->type_data.request.method == GST_RTSP_POST) {
++      msg->type_data.request.method = GST_RTSP_INVALID;
++      if (res == GST_RTSP_OK)
++        res = GST_RTSP_ERROR;
++    }
++  } else if (msg->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
++    /* only GET and POST are allowed as HTTP methods */
++    if (msg->type_data.request.method != GST_RTSP_GET &&
++        msg->type_data.request.method != GST_RTSP_POST) {
++      msg->type_data.request.method = GST_RTSP_INVALID;
++      if (res == GST_RTSP_OK)
++        res = GST_RTSP_ERROR;
++    }
++  }
++
++  return res;
++}
++
++/* parsing lines means reading a Key: Value pair */
++static GstRTSPResult
++parse_line (guint8 * buffer, GstRTSPMessage * msg)
++{
++  GstRTSPHeaderField field;
++  gchar *line = (gchar *) buffer;
++  gchar *value;
++
++  if ((value = strchr (line, ':')) == NULL || value == line)
++    goto parse_error;
++
++  /* trim space before the colon */
++  if (value[-1] == ' ')
++    value[-1] = '\0';
++
++  /* replace the colon with a NUL */
++  *value++ = '\0';
++
++  /* find the header */
++  field = gst_rtsp_find_header_field (line);
++  if (field == GST_RTSP_HDR_INVALID)
++    goto done;
++
++  /* split up the value in multiple key:value pairs if it contains comma(s) */
++  while (*value != '\0') {
++    gchar *next_value;
++    gchar *comma = NULL;
++    gboolean quoted = FALSE;
++    guint comment = 0;
++
++    /* trim leading space */
++    if (*value == ' ')
++      value++;
++
++    /* for headers which may not appear multiple times, and thus may not
++     * contain multiple values on the same line, we can short-circuit the loop
++     * below and the entire value results in just one key:value pair*/
++    if (!gst_rtsp_header_allow_multiple (field))
++      next_value = value + strlen (value);
++    else
++      next_value = value;
++
++    /* find the next value, taking special care of quotes and comments */
++    while (*next_value != '\0') {
++      if ((quoted || comment != 0) && *next_value == '\\' &&
++          next_value[1] != '\0')
++        next_value++;
++      else if (comment == 0 && *next_value == '"')
++        quoted = !quoted;
++      else if (!quoted && *next_value == '(')
++        comment++;
++      else if (comment != 0 && *next_value == ')')
++        comment--;
++      else if (!quoted && comment == 0) {
++        /* To quote RFC 2068: "User agents MUST take special care in parsing
++         * the WWW-Authenticate field value if it contains more than one
++         * challenge, or if more than one WWW-Authenticate header field is
++         * provided, since the contents of a challenge may itself contain a
++         * comma-separated list of authentication parameters."
++         *
++         * What this means is that we cannot just look for an unquoted comma
++         * when looking for multiple values in Proxy-Authenticate and
++         * WWW-Authenticate headers. Instead we need to look for the sequence
++         * "comma [space] token space token" before we can split after the
++         * comma...
++         */
++        if (field == GST_RTSP_HDR_PROXY_AUTHENTICATE ||
++            field == GST_RTSP_HDR_WWW_AUTHENTICATE) {
++          if (*next_value == ',') {
++            if (next_value[1] == ' ') {
++              /* skip any space following the comma so we do not mistake it for
++               * separating between two tokens */
++              next_value++;
++            }
++            comma = next_value;
++          } else if (*next_value == ' ' && next_value[1] != ',' &&
++              next_value[1] != '=' && comma != NULL) {
++            next_value = comma;
++            comma = NULL;
++            break;
++          }
++        } else if (*next_value == ',')
++          break;
++      }
++
++      next_value++;
++    }
++
++    /* trim space */
++    if (value != next_value && next_value[-1] == ' ')
++      next_value[-1] = '\0';
++
++    if (*next_value != '\0')
++      *next_value++ = '\0';
++
++    /* add the key:value pair */
++    if (*value != '\0')
++      gst_rtsp_message_add_header (msg, field, value);
++
++    value = next_value;
++  }
++
++done:
++  return GST_RTSP_OK;
++
++  /* ERRORS */
++parse_error:
++  {
++    return GST_RTSP_EPARSE;
++  }
++}
++
++/* convert all consecutive whitespace to a single space */
++static void
++normalize_line (guint8 * buffer)
++{
++  while (*buffer) {
++    if (g_ascii_isspace (*buffer)) {
++      guint8 *tmp;
++
++      *buffer++ = ' ';
++      for (tmp = buffer; g_ascii_isspace (*tmp); tmp++) {
++      }
++      if (buffer != tmp)
++        memmove (buffer, tmp, strlen ((gchar *) tmp) + 1);
++    } else {
++      buffer++;
++    }
++  }
++}
++
++/* returns:
++ *  GST_RTSP_OK when a complete message was read.
++ *  GST_RTSP_EEOF: when the socket is closed
++ *  GST_RTSP_EINTR: when more data is needed.
++ *  GST_RTSP_..: some other error occured.
++ */
++static GstRTSPResult
++build_next (GstRTSPBuilder * builder, GstRTSPMessage * message,
++    GstRTSPConnection * conn)
++{
++  GstRTSPResult res;
++
++  while (TRUE) {
++    switch (builder->state) {
++      case STATE_START:
++        builder->offset = 0;
++        res =
++            read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 1);
++        if (res != GST_RTSP_OK)
++          goto done;
++
++        /* we have 1 bytes now and we can see if this is a data message or
++         * not */
++        if (builder->buffer[0] == '$') {
++          /* data message, prepare for the header */
++          builder->state = STATE_DATA_HEADER;
++        } else {
++          builder->line = 0;
++          builder->state = STATE_READ_LINES;
++        }
++        break;
++      case STATE_DATA_HEADER:
++      {
++        res =
++            read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 4);
++        if (res != GST_RTSP_OK)
++          goto done;
++
++        gst_rtsp_message_init_data (message, builder->buffer[1]);
++
++        builder->body_len = (builder->buffer[2] << 8) | builder->buffer[3];
++        builder->body_data = g_malloc (builder->body_len + 1);
++        builder->body_data[builder->body_len] = '\0';
++        builder->offset = 0;
++        builder->state = STATE_DATA_BODY;
++        break;
++      }
++      case STATE_DATA_BODY:
++      {
++        res =
++            read_bytes (conn, builder->body_data, &builder->offset,
++            builder->body_len);
++        if (res != GST_RTSP_OK)
++          goto done;
++
++        /* we have the complete body now, store in the message adjusting the
++         * length to include the traling '\0' */
++        gst_rtsp_message_take_body (message,
++            (guint8 *) builder->body_data, builder->body_len + 1);
++        builder->body_data = NULL;
++        builder->body_len = 0;
++
++        builder->state = STATE_END;
++        break;
++      }
++      case STATE_READ_LINES:
++      {
++        res = read_line (conn, builder->buffer, &builder->offset,
++            sizeof (builder->buffer));
++        if (res != GST_RTSP_OK)
++          goto done;
++
++        /* we have a regular response */
++        if (builder->buffer[0] == '\0') {
++          gchar *hdrval;
++
++          /* empty line, end of message header */
++          /* see if there is a Content-Length header, but ignore it if this
++           * is a POST request with an x-sessioncookie header */
++          if (gst_rtsp_message_get_header (message,
++                  GST_RTSP_HDR_CONTENT_LENGTH, &hdrval, 0) == GST_RTSP_OK &&
++              (message->type != GST_RTSP_MESSAGE_HTTP_REQUEST ||
++                  message->type_data.request.method != GST_RTSP_POST ||
++                  gst_rtsp_message_get_header (message,
++                      GST_RTSP_HDR_X_SESSIONCOOKIE, NULL, 0) != GST_RTSP_OK)) {
++            /* there is, prepare to read the body */
++            builder->body_len = atol (hdrval);
++            builder->body_data = g_malloc (builder->body_len + 1);
++            builder->body_data[builder->body_len] = '\0';
++            builder->offset = 0;
++            builder->state = STATE_DATA_BODY;
++          } else {
++            builder->state = STATE_END;
++          }
++          break;
++        }
++
++        /* we have a line */
++        normalize_line (builder->buffer);
++        if (builder->line == 0) {
++          /* first line, check for response status */
++          if (memcmp (builder->buffer, "RTSP", 4) == 0 ||
++              memcmp (builder->buffer, "HTTP", 4) == 0) {
++            builder->status = parse_response_status (builder->buffer, message);
++          } else {
++            builder->status = parse_request_line (builder->buffer, message);
++          }
++        } else {
++          /* else just parse the line */
++          res = parse_line (builder->buffer, message);
++          if (res != GST_RTSP_OK)
++            builder->status = res;
++        }
++        builder->line++;
++        builder->offset = 0;
++        break;
++      }
++      case STATE_END:
++      {
++        gchar *session_cookie;
++        gchar *session_id;
++
++        if (message->type == GST_RTSP_MESSAGE_DATA) {
++          /* data messages don't have headers */
++          res = GST_RTSP_OK;
++          goto done;
++        }
++
++        /* save the tunnel session in the connection */
++        if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST &&
++            !conn->manual_http &&
++            conn->tstate == TUNNEL_STATE_NONE &&
++            gst_rtsp_message_get_header (message, GST_RTSP_HDR_X_SESSIONCOOKIE,
++                &session_cookie, 0) == GST_RTSP_OK) {
++          strncpy (conn->tunnelid, session_cookie, TUNNELID_LEN);
++          conn->tunnelid[TUNNELID_LEN - 1] = '\0';
++          conn->tunneled = TRUE;
++        }
++
++        /* save session id in the connection for further use */
++        if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
++            gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
++                &session_id, 0) == GST_RTSP_OK) {
++          gint maxlen, i;
++
++          maxlen = sizeof (conn->session_id) - 1;
++          /* the sessionid can have attributes marked with ;
++           * Make sure we strip them */
++          for (i = 0; session_id[i] != '\0'; i++) {
++            if (session_id[i] == ';') {
++              maxlen = i;
++              /* parse timeout */
++              do {
++                i++;
++              } while (g_ascii_isspace (session_id[i]));
++              if (g_str_has_prefix (&session_id[i], "timeout=")) {
++                gint to;
++
++                /* if we parsed something valid, configure */
++                if ((to = atoi (&session_id[i + 8])) > 0)
++                  conn->timeout = to;
++              }
++              break;
++            }
++          }
++
++          /* make sure to not overflow */
++          strncpy (conn->session_id, session_id, maxlen);
++          conn->session_id[maxlen] = '\0';
++        }
++        res = builder->status;
++        goto done;
++      }
++      default:
++        res = GST_RTSP_ERROR;
++        break;
++    }
++  }
++done:
++  return res;
++}
++
++/**
++ * gst_rtsp_connection_read:
++ * @conn: a #GstRTSPConnection
++ * @data: the data to read
++ * @size: the size of @data
++ * @timeout: a timeout value or #NULL
++ *
++ * Attempt to read @size bytes into @data from the connected @conn, blocking up to
++ * the specified @timeout. @timeout can be #NULL, in which case this function
++ * might block forever.
++ *
++ * This function can be cancelled with gst_rtsp_connection_flush().
++ *
++ * Returns: #GST_RTSP_OK on success.
++ */
++GstRTSPResult
++gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
++    GTimeVal * timeout)
++{
++  guint offset;
++  gint retval;
++  GstClockTime to;
++  GstRTSPResult res;
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
++
++  if (G_UNLIKELY (size == 0))
++    return GST_RTSP_OK;
++
++  offset = 0;
++
++  /* configure timeout if any */
++  to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
++
++  gst_poll_set_controllable (conn->fdset, TRUE);
++  gst_poll_fd_ctl_write (conn->fdset, conn->writefd, FALSE);
++  gst_poll_fd_ctl_read (conn->fdset, conn->readfd, TRUE);
++
++  while (TRUE) {
++    res = read_bytes (conn, data, &offset, size);
++    if (G_UNLIKELY (res == GST_RTSP_EEOF))
++      goto eof;
++    if (G_LIKELY (res == GST_RTSP_OK))
++      break;
++    if (G_UNLIKELY (res != GST_RTSP_EINTR))
++      goto read_error;
++
++    do {
++      retval = gst_poll_wait (conn->fdset, to);
++    } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
++
++    /* check for timeout */
++    if (G_UNLIKELY (retval == 0))
++      goto select_timeout;
++
++    if (G_UNLIKELY (retval == -1)) {
++      if (errno == EBUSY)
++        goto stopped;
++      else
++        goto select_error;
++    }
++    gst_poll_set_controllable (conn->fdset, FALSE);
++  }
++  return GST_RTSP_OK;
++
++  /* ERRORS */
++select_error:
++  {
++    return GST_RTSP_ESYS;
++  }
++select_timeout:
++  {
++    return GST_RTSP_ETIMEOUT;
++  }
++stopped:
++  {
++    return GST_RTSP_EINTR;
++  }
++eof:
++  {
++    return GST_RTSP_EEOF;
++  }
++read_error:
++  {
++    return res;
++  }
++}
++
++static GstRTSPMessage *
++gen_tunnel_reply (GstRTSPConnection * conn, GstRTSPStatusCode code,
++    const GstRTSPMessage * request)
++{
++  GstRTSPMessage *msg;
++  GstRTSPResult res;
++
++  if (gst_rtsp_status_as_text (code) == NULL)
++    code = GST_RTSP_STS_INTERNAL_SERVER_ERROR;
++
++  GST_RTSP_CHECK (gst_rtsp_message_new_response (&msg, code, NULL, request),
++      no_message);
++
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_SERVER,
++      "GStreamer RTSP Server");
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONNECTION, "close");
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-store");
++  gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
++
++  if (code == GST_RTSP_STS_OK) {
++    if (conn->ip)
++      gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
++          conn->ip);
++    gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_TYPE,
++        "application/x-rtsp-tunnelled");
++  }
++
++  return msg;
++
++  /* ERRORS */
++no_message:
++  {
++    return NULL;
++  }
++}
++
++/**
++ * gst_rtsp_connection_receive:
++ * @conn: a #GstRTSPConnection
++ * @message: the message to read
++ * @timeout: a timeout value or #NULL
++ *
++ * Attempt to read into @message from the connected @conn, blocking up to
++ * the specified @timeout. @timeout can be #NULL, in which case this function
++ * might block forever.
++ * 
++ * This function can be cancelled with gst_rtsp_connection_flush().
++ *
++ * Returns: #GST_RTSP_OK on success.
++ */
++GstRTSPResult
++gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
++    GTimeVal * timeout)
++{
++  GstRTSPResult res;
++  GstRTSPBuilder builder;
++  gint retval;
++  GstClockTime to;
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
++
++  /* configure timeout if any */
++  to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
++
++  gst_poll_set_controllable (conn->fdset, TRUE);
++  gst_poll_fd_ctl_write (conn->fdset, conn->writefd, FALSE);
++  gst_poll_fd_ctl_read (conn->fdset, conn->readfd, TRUE);
++
++  memset (&builder, 0, sizeof (GstRTSPBuilder));
++  while (TRUE) {
++    res = build_next (&builder, message, conn);
++    if (G_UNLIKELY (res == GST_RTSP_EEOF))
++      goto eof;
++    else if (G_LIKELY (res == GST_RTSP_OK)) {
++      if (!conn->manual_http) {
++        if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
++          if (conn->tstate == TUNNEL_STATE_NONE &&
++              message->type_data.request.method == GST_RTSP_GET) {
++            GstRTSPMessage *response;
++
++            conn->tstate = TUNNEL_STATE_GET;
++
++            /* tunnel GET request, we can reply now */
++            response = gen_tunnel_reply (conn, GST_RTSP_STS_OK, message);
++            res = gst_rtsp_connection_send (conn, response, timeout);
++            gst_rtsp_message_free (response);
++            if (res == GST_RTSP_OK)
++              res = GST_RTSP_ETGET;
++            goto cleanup;
++          } else if (conn->tstate == TUNNEL_STATE_NONE &&
++              message->type_data.request.method == GST_RTSP_POST) {
++            conn->tstate = TUNNEL_STATE_POST;
++
++            /* tunnel POST request, the caller now has to link the two
++             * connections. */
++            res = GST_RTSP_ETPOST;
++            goto cleanup;
++          } else {
++            res = GST_RTSP_EPARSE;
++            goto cleanup;
++          }
++        } else if (message->type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
++          res = GST_RTSP_EPARSE;
++          goto cleanup;
++        }
++      }
++
++      break;
++    } else if (G_UNLIKELY (res != GST_RTSP_EINTR))
++      goto read_error;
++
++    do {
++      retval = gst_poll_wait (conn->fdset, to);
++    } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
++
++    /* check for timeout */
++    if (G_UNLIKELY (retval == 0))
++      goto select_timeout;
++
++    if (G_UNLIKELY (retval == -1)) {
++      if (errno == EBUSY)
++        goto stopped;
++      else
++        goto select_error;
++    }
++    gst_poll_set_controllable (conn->fdset, FALSE);
++  }
++
++  /* we have a message here */
++  build_reset (&builder);
++
++  return GST_RTSP_OK;
++
++  /* ERRORS */
++select_error:
++  {
++    res = GST_RTSP_ESYS;
++    goto cleanup;
++  }
++select_timeout:
++  {
++    res = GST_RTSP_ETIMEOUT;
++    goto cleanup;
++  }
++stopped:
++  {
++    res = GST_RTSP_EINTR;
++    goto cleanup;
++  }
++eof:
++  {
++    res = GST_RTSP_EEOF;
++    goto cleanup;
++  }
++read_error:
++cleanup:
++  {
++    build_reset (&builder);
++    gst_rtsp_message_unset (message);
++    return res;
++  }
++}
++
++/**
++ * gst_rtsp_connection_close:
++ * @conn: a #GstRTSPConnection
++ *
++ * Close the connected @conn. After this call, the connection is in the same
++ * state as when it was first created.
++ * 
++ * Returns: #GST_RTSP_OK on success.
++ */
++GstRTSPResult
++gst_rtsp_connection_close (GstRTSPConnection * conn)
++{
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++  g_free (conn->ip);
++  conn->ip = NULL;
++
++  conn->read_ahead = 0;
++
++  g_free (conn->initial_buffer);
++  conn->initial_buffer = NULL;
++  conn->initial_buffer_offset = 0;
++
++  REMOVE_POLLFD (conn->fdset, &conn->fd0);
++  REMOVE_POLLFD (conn->fdset, &conn->fd1);
++  conn->writefd = NULL;
++  conn->readfd = NULL;
++  conn->tunneled = FALSE;
++  conn->tstate = TUNNEL_STATE_NONE;
++  conn->ctxp = NULL;
++  g_free (conn->username);
++  conn->username = NULL;
++  g_free (conn->passwd);
++  conn->passwd = NULL;
++  gst_rtsp_connection_clear_auth_params (conn);
++  conn->timeout = 60;
++  conn->cseq = 0;
++  conn->session_id[0] = '\0';
++
++  return GST_RTSP_OK;
++}
++
++/**
++ * gst_rtsp_connection_free:
++ * @conn: a #GstRTSPConnection
++ *
++ * Close and free @conn.
++ * 
++ * Returns: #GST_RTSP_OK on success.
++ */
++GstRTSPResult
++gst_rtsp_connection_free (GstRTSPConnection * conn)
++{
++  GstRTSPResult res;
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++  res = gst_rtsp_connection_close (conn);
++  gst_poll_free (conn->fdset);
++  g_timer_destroy (conn->timer);
++  gst_rtsp_url_free (conn->url);
++  g_free (conn->proxy_host);
++  g_free (conn);
++#ifdef G_OS_WIN32
++  WSACleanup ();
++#endif
++
++  return res;
++}
++
++/**
++ * gst_rtsp_connection_poll:
++ * @conn: a #GstRTSPConnection
++ * @events: a bitmask of #GstRTSPEvent flags to check
++ * @revents: location for result flags 
++ * @timeout: a timeout
++ *
++ * Wait up to the specified @timeout for the connection to become available for
++ * at least one of the operations specified in @events. When the function returns
++ * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
++ * @conn.
++ *
++ * @timeout can be #NULL, in which case this function might block forever.
++ *
++ * This function can be cancelled with gst_rtsp_connection_flush().
++ * 
++ * Returns: #GST_RTSP_OK on success.
++ *
++ * Since: 0.10.15
++ */
++GstRTSPResult
++gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
++    GstRTSPEvent * revents, GTimeVal * timeout)
++{
++  GstClockTime to;
++  gint retval;
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
++  g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL);
++
++  gst_poll_set_controllable (conn->fdset, TRUE);
++
++  /* add fd to writer set when asked to */
++  gst_poll_fd_ctl_write (conn->fdset, conn->writefd,
++      events & GST_RTSP_EV_WRITE);
++
++  /* add fd to reader set when asked to */
++  gst_poll_fd_ctl_read (conn->fdset, conn->readfd, events & GST_RTSP_EV_READ);
++
++  /* configure timeout if any */
++  to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
++
++  do {
++    retval = gst_poll_wait (conn->fdset, to);
++  } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
++
++  if (G_UNLIKELY (retval == 0))
++    goto select_timeout;
++
++  if (G_UNLIKELY (retval == -1)) {
++    if (errno == EBUSY)
++      goto stopped;
++    else
++      goto select_error;
++  }
++
++  *revents = 0;
++  if (events & GST_RTSP_EV_READ) {
++    if (gst_poll_fd_can_read (conn->fdset, conn->readfd))
++      *revents |= GST_RTSP_EV_READ;
++  }
++  if (events & GST_RTSP_EV_WRITE) {
++    if (gst_poll_fd_can_write (conn->fdset, conn->writefd))
++      *revents |= GST_RTSP_EV_WRITE;
++  }
++  return GST_RTSP_OK;
++
++  /* ERRORS */
++select_timeout:
++  {
++    return GST_RTSP_ETIMEOUT;
++  }
++select_error:
++  {
++    return GST_RTSP_ESYS;
++  }
++stopped:
++  {
++    return GST_RTSP_EINTR;
++  }
++}
++
++/**
++ * gst_rtsp_connection_next_timeout:
++ * @conn: a #GstRTSPConnection
++ * @timeout: a timeout
++ *
++ * Calculate the next timeout for @conn, storing the result in @timeout.
++ * 
++ * Returns: #GST_RTSP_OK.
++ */
++GstRTSPResult
++gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
++{
++  gdouble elapsed;
++  glong sec;
++  gulong usec;
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
++
++  elapsed = g_timer_elapsed (conn->timer, &usec);
++  if (elapsed >= conn->timeout) {
++    sec = 0;
++    usec = 0;
++  } else {
++    sec = conn->timeout - elapsed;
++  }
++
++  timeout->tv_sec = sec;
++  timeout->tv_usec = usec;
++
++  return GST_RTSP_OK;
++}
++
++/**
++ * gst_rtsp_connection_reset_timeout:
++ * @conn: a #GstRTSPConnection
++ *
++ * Reset the timeout of @conn.
++ * 
++ * Returns: #GST_RTSP_OK.
++ */
++GstRTSPResult
++gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
++{
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++  g_timer_start (conn->timer);
++
++  return GST_RTSP_OK;
++}
++
++/**
++ * gst_rtsp_connection_flush:
++ * @conn: a #GstRTSPConnection
++ * @flush: start or stop the flush
++ *
++ * Start or stop the flushing action on @conn. When flushing, all current
++ * and future actions on @conn will return #GST_RTSP_EINTR until the connection
++ * is set to non-flushing mode again.
++ * 
++ * Returns: #GST_RTSP_OK.
++ */
++GstRTSPResult
++gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
++{
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++  gst_poll_set_flushing (conn->fdset, flush);
++
++  return GST_RTSP_OK;
++}
++
++/**
++ * gst_rtsp_connection_set_proxy:
++ * @conn: a #GstRTSPConnection
++ * @host: the proxy host
++ * @port: the proxy port
++ *
++ * Set the proxy host and port.
++ * 
++ * Returns: #GST_RTSP_OK.
++ *
++ * Since: 0.10.23
++ */
++GstRTSPResult
++gst_rtsp_connection_set_proxy (GstRTSPConnection * conn,
++    const gchar * host, guint port)
++{
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++  g_free (conn->proxy_host);
++  conn->proxy_host = g_strdup (host);
++  conn->proxy_port = port;
++
++  return GST_RTSP_OK;
++}
++
++/**
++ * gst_rtsp_connection_set_auth:
++ * @conn: a #GstRTSPConnection
++ * @method: authentication method
++ * @user: the user
++ * @pass: the password
++ *
++ * Configure @conn for authentication mode @method with @user and @pass as the
++ * user and password respectively.
++ * 
++ * Returns: #GST_RTSP_OK.
++ */
++GstRTSPResult
++gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
++    GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
++{
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++  if (method == GST_RTSP_AUTH_DIGEST && ((user == NULL || pass == NULL)
++          || g_strrstr (user, ":") != NULL))
++    return GST_RTSP_EINVAL;
++
++  /* Make sure the username and passwd are being set for authentication */
++  if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
++    return GST_RTSP_EINVAL;
++
++  /* ":" chars are not allowed in usernames for basic auth */
++  if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
++    return GST_RTSP_EINVAL;
++
++  g_free (conn->username);
++  g_free (conn->passwd);
++
++  conn->auth_method = method;
++  conn->username = g_strdup (user);
++  conn->passwd = g_strdup (pass);
++
++  return GST_RTSP_OK;
++}
++
++/**
++ * str_case_hash:
++ * @key: ASCII string to hash
++ *
++ * Hashes @key in a case-insensitive manner.
++ *
++ * Returns: the hash code.
++ **/
++static guint
++str_case_hash (gconstpointer key)
++{
++  const char *p = key;
++  guint h = g_ascii_toupper (*p);
++
++  if (h)
++    for (p += 1; *p != '\0'; p++)
++      h = (h << 5) - h + g_ascii_toupper (*p);
++
++  return h;
++}
++
++/**
++ * str_case_equal:
++ * @v1: an ASCII string
++ * @v2: another ASCII string
++ *
++ * Compares @v1 and @v2 in a case-insensitive manner
++ *
++ * Returns: %TRUE if they are equal (modulo case)
++ **/
++static gboolean
++str_case_equal (gconstpointer v1, gconstpointer v2)
++{
++  const char *string1 = v1;
++  const char *string2 = v2;
++
++  return g_ascii_strcasecmp (string1, string2) == 0;
++}
++
++/**
++ * gst_rtsp_connection_set_auth_param:
++ * @conn: a #GstRTSPConnection
++ * @param: authentication directive
++ * @value: value
++ *
++ * Setup @conn with authentication directives. This is not necesary for
++ * methods #GST_RTSP_AUTH_NONE and #GST_RTSP_AUTH_BASIC. For
++ * #GST_RTSP_AUTH_DIGEST, directives should be taken from the digest challenge
++ * in the WWW-Authenticate response header and can include realm, domain,
++ * nonce, opaque, stale, algorithm, qop as per RFC2617.
++ * 
++ * Since: 0.10.20
++ */
++void
++gst_rtsp_connection_set_auth_param (GstRTSPConnection * conn,
++    const gchar * param, const gchar * value)
++{
++  g_return_if_fail (conn != NULL);
++  g_return_if_fail (param != NULL);
++
++  if (conn->auth_params == NULL) {
++    conn->auth_params =
++        g_hash_table_new_full (str_case_hash, str_case_equal, g_free, g_free);
++  }
++  g_hash_table_insert (conn->auth_params, g_strdup (param), g_strdup (value));
++}
++
++/**
++ * gst_rtsp_connection_clear_auth_params:
++ * @conn: a #GstRTSPConnection
++ *
++ * Clear the list of authentication directives stored in @conn.
++ *
++ * Since: 0.10.20
++ */
++void
++gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn)
++{
++  g_return_if_fail (conn != NULL);
++
++  if (conn->auth_params != NULL) {
++    g_hash_table_destroy (conn->auth_params);
++    conn->auth_params = NULL;
++  }
++}
++
++static GstRTSPResult
++set_qos_dscp (gint fd, guint qos_dscp)
++{
++  union gst_sockaddr sa;
++  socklen_t slen = sizeof (sa);
++  gint af;
++  gint tos;
++
++  if (fd == -1)
++    return GST_RTSP_OK;
++
++  if (getsockname (fd, &sa.sa, &slen) < 0)
++    goto no_getsockname;
++
++  af = sa.sa.sa_family;
++
++  /* if this is an IPv4-mapped address then do IPv4 QoS */
++  if (af == AF_INET6) {
++    if (IN6_IS_ADDR_V4MAPPED (&sa.sa_in6.sin6_addr))
++      af = AF_INET;
++  }
++
++  /* extract and shift 6 bits of the DSCP */
++  tos = (qos_dscp & 0x3f) << 2;
++
++  switch (af) {
++    case AF_INET:
++      if (SETSOCKOPT (fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0)
++        goto no_setsockopt;
++      break;
++    case AF_INET6:
++#ifdef IPV6_TCLASS
++      if (SETSOCKOPT (fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof (tos)) < 0)
++        goto no_setsockopt;
++      break;
++#endif
++    default:
++      goto wrong_family;
++  }
++
++  return GST_RTSP_OK;
++
++  /* ERRORS */
++no_getsockname:
++no_setsockopt:
++  {
++    return GST_RTSP_ESYS;
++  }
++
++wrong_family:
++  {
++    return GST_RTSP_ERROR;
++  }
++}
++
++/**
++ * gst_rtsp_connection_set_qos_dscp:
++ * @conn: a #GstRTSPConnection
++ * @qos_dscp: DSCP value
++ *
++ * Configure @conn to use the specified DSCP value.
++ *
++ * Returns: #GST_RTSP_OK on success.
++ *
++ * Since: 0.10.20
++ */
++GstRTSPResult
++gst_rtsp_connection_set_qos_dscp (GstRTSPConnection * conn, guint qos_dscp)
++{
++  GstRTSPResult res;
++
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL);
++
++  res = set_qos_dscp (conn->fd0.fd, qos_dscp);
++  if (res == GST_RTSP_OK)
++    res = set_qos_dscp (conn->fd1.fd, qos_dscp);
++
++  return res;
++}
++
++
++/**
++ * gst_rtsp_connection_get_url:
++ * @conn: a #GstRTSPConnection
++ *
++ * Retrieve the URL of the other end of @conn.
++ *
++ * Returns: The URL. This value remains valid until the
++ * connection is freed.
++ *
++ * Since: 0.10.23
++ */
++GstRTSPUrl *
++gst_rtsp_connection_get_url (const GstRTSPConnection * conn)
++{
++  g_return_val_if_fail (conn != NULL, NULL);
++
++  return conn->url;
++}
++
++/**
++ * gst_rtsp_connection_get_ip:
++ * @conn: a #GstRTSPConnection
++ *
++ * Retrieve the IP address of the other end of @conn.
++ *
++ * Returns: The IP address as a string. this value remains valid until the
++ * connection is closed.
++ *
++ * Since: 0.10.20
++ */
++const gchar *
++gst_rtsp_connection_get_ip (const GstRTSPConnection * conn)
++{
++  g_return_val_if_fail (conn != NULL, NULL);
++
++  return conn->ip;
++}
++
++/**
++ * gst_rtsp_connection_set_ip:
++ * @conn: a #GstRTSPConnection
++ * @ip: an ip address
++ *
++ * Set the IP address of the server.
++ *
++ * Since: 0.10.23
++ */
++void
++gst_rtsp_connection_set_ip (GstRTSPConnection * conn, const gchar * ip)
++{
++  g_return_if_fail (conn != NULL);
++
++  g_free (conn->ip);
++  conn->ip = g_strdup (ip);
++}
++
++/**
++ * gst_rtsp_connection_get_readfd:
++ * @conn: a #GstRTSPConnection
++ *
++ * Get the file descriptor for reading.
++ *
++ * Returns: the file descriptor used for reading or -1 on error. The file
++ * descriptor remains valid until the connection is closed.
++ *
++ * Since: 0.10.23
++ */
++gint
++gst_rtsp_connection_get_readfd (const GstRTSPConnection * conn)
++{
++  g_return_val_if_fail (conn != NULL, -1);
++  g_return_val_if_fail (conn->readfd != NULL, -1);
++
++  return conn->readfd->fd;
++}
++
++/**
++ * gst_rtsp_connection_get_writefd:
++ * @conn: a #GstRTSPConnection
++ *
++ * Get the file descriptor for writing.
++ *
++ * Returns: the file descriptor used for writing or -1 on error. The file
++ * descriptor remains valid until the connection is closed.
++ *
++ * Since: 0.10.23
++ */
++gint
++gst_rtsp_connection_get_writefd (const GstRTSPConnection * conn)
++{
++  g_return_val_if_fail (conn != NULL, -1);
++  g_return_val_if_fail (conn->writefd != NULL, -1);
++
++  return conn->writefd->fd;
++}
++
++/**
++ * gst_rtsp_connection_set_http_mode:
++ * @conn: a #GstRTSPConnection
++ * @enable: %TRUE to enable manual HTTP mode
++ *
++ * By setting the HTTP mode to %TRUE the message parsing will support HTTP
++ * messages in addition to the RTSP messages. It will also disable the
++ * automatic handling of setting up an HTTP tunnel.
++ *
++ * Since: 0.10.25
++ */
++void
++gst_rtsp_connection_set_http_mode (GstRTSPConnection * conn, gboolean enable)
++{
++  g_return_if_fail (conn != NULL);
++
++  conn->manual_http = enable;
++}
++
++/**
++ * gst_rtsp_connection_set_tunneled:
++ * @conn: a #GstRTSPConnection
++ * @tunneled: the new state
++ *
++ * Set the HTTP tunneling state of the connection. This must be configured before
++ * the @conn is connected.
++ *
++ * Since: 0.10.23
++ */
++void
++gst_rtsp_connection_set_tunneled (GstRTSPConnection * conn, gboolean tunneled)
++{
++  g_return_if_fail (conn != NULL);
++  g_return_if_fail (conn->readfd == NULL);
++  g_return_if_fail (conn->writefd == NULL);
++
++  conn->tunneled = tunneled;
++}
++
++/**
++ * gst_rtsp_connection_is_tunneled:
++ * @conn: a #GstRTSPConnection
++ *
++ * Get the tunneling state of the connection. 
++ *
++ * Returns: if @conn is using HTTP tunneling.
++ *
++ * Since: 0.10.23
++ */
++gboolean
++gst_rtsp_connection_is_tunneled (const GstRTSPConnection * conn)
++{
++  g_return_val_if_fail (conn != NULL, FALSE);
++
++  return conn->tunneled;
++}
++
++/**
++ * gst_rtsp_connection_get_tunnelid:
++ * @conn: a #GstRTSPConnection
++ *
++ * Get the tunnel session id the connection. 
++ *
++ * Returns: returns a non-empty string if @conn is being tunneled over HTTP.
++ *
++ * Since: 0.10.23
++ */
++const gchar *
++gst_rtsp_connection_get_tunnelid (const GstRTSPConnection * conn)
++{
++  g_return_val_if_fail (conn != NULL, NULL);
++
++  if (!conn->tunneled)
++    return NULL;
++
++  return conn->tunnelid;
++}
++
++/**
++ * gst_rtsp_connection_do_tunnel:
++ * @conn: a #GstRTSPConnection
++ * @conn2: a #GstRTSPConnection or %NULL
++ *
++ * If @conn received the first tunnel connection and @conn2 received
++ * the second tunnel connection, link the two connections together so that
++ * @conn manages the tunneled connection.
++ *
++ * After this call, @conn2 cannot be used anymore and must be freed with
++ * gst_rtsp_connection_free().
++ *
++ * If @conn2 is %NULL then only the base64 decoding context will be setup for
++ * @conn.
++ *
++ * Returns: return GST_RTSP_OK on success.
++ *
++ * Since: 0.10.23
++ */
++GstRTSPResult
++gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn,
++    GstRTSPConnection * conn2)
++{
++  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
++
++  if (conn2 != NULL) {
++    g_return_val_if_fail (conn->tstate == TUNNEL_STATE_GET, GST_RTSP_EINVAL);
++    g_return_val_if_fail (conn2->tstate == TUNNEL_STATE_POST, GST_RTSP_EINVAL);
++    g_return_val_if_fail (!memcmp (conn2->tunnelid, conn->tunnelid,
++            TUNNELID_LEN), GST_RTSP_EINVAL);
++
++    /* both connections have fd0 as the read/write socket. start by taking the
++     * socket from conn2 and set it as the socket in conn */
++    conn->fd1 = conn2->fd0;
++
++    /* clean up some of the state of conn2 */
++    gst_poll_remove_fd (conn2->fdset, &conn2->fd0);
++    conn2->fd0.fd = -1;
++    conn2->readfd = conn2->writefd = NULL;
++
++    /* We make fd0 the write socket and fd1 the read socket. */
++    conn->writefd = &conn->fd0;
++    conn->readfd = &conn->fd1;
++
++    conn->tstate = TUNNEL_STATE_COMPLETE;
++  }
++
++  /* we need base64 decoding for the readfd */
++  conn->ctx.state = 0;
++  conn->ctx.save = 0;
++  conn->ctx.cout = 0;
++  conn->ctx.coutl = 0;
++  conn->ctxp = &conn->ctx;
++
++  return GST_RTSP_OK;
++}
++
++#define READ_COND   (G_IO_IN | G_IO_HUP | G_IO_ERR)
++#define WRITE_COND  (G_IO_OUT | G_IO_ERR)
++
++typedef struct
++{
++  guint8 *data;
++  guint size;
++  guint id;
++} GstRTSPRec;
++
++/* async functions */
++struct _GstRTSPWatch
++{
++  GSource source;
++
++  GstRTSPConnection *conn;
++
++  GstRTSPBuilder builder;
++  GstRTSPMessage message;
++
++  GPollFD readfd;
++  GPollFD writefd;
++  gboolean write_added;
++
++  /* queued message for transmission */
++  guint id;
++  GMutex *mutex;
++  GQueue *messages;
++  guint8 *write_data;
++  guint write_off;
++  guint write_size;
++  guint write_id;
++
++  GstRTSPWatchFuncs funcs;
++
++  gpointer user_data;
++  GDestroyNotify notify;
++};
++
++static gboolean
++gst_rtsp_source_prepare (GSource * source, gint * timeout)
++{
++  GstRTSPWatch *watch = (GstRTSPWatch *) source;
++
++  if (watch->conn->initial_buffer != NULL)
++    return TRUE;
++
++  *timeout = (watch->conn->timeout * 1000);
++
++  return FALSE;
++}
++
++static gboolean
++gst_rtsp_source_check (GSource * source)
++{
++  GstRTSPWatch *watch = (GstRTSPWatch *) source;
++
++  if (watch->readfd.revents & READ_COND)
++    return TRUE;
++
++  if (watch->writefd.revents & WRITE_COND)
++    return TRUE;
++
++  return FALSE;
++}
++
++static gboolean
++gst_rtsp_source_dispatch (GSource * source, GSourceFunc callback G_GNUC_UNUSED,
++    gpointer user_data G_GNUC_UNUSED)
++{
++  GstRTSPWatch *watch = (GstRTSPWatch *) source;
++  GstRTSPResult res;
++
++  /* first read as much as we can */
++  if (watch->readfd.revents & READ_COND || watch->conn->initial_buffer != NULL) {
++    do {
++      res = build_next (&watch->builder, &watch->message, watch->conn);
++      if (res == GST_RTSP_EINTR)
++        break;
++      else if (G_UNLIKELY (res == GST_RTSP_EEOF))
++        goto eof;
++      else if (G_LIKELY (res == GST_RTSP_OK)) {
++        if (!watch->conn->manual_http &&
++            watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
++          if (watch->conn->tstate == TUNNEL_STATE_NONE &&
++              watch->message.type_data.request.method == GST_RTSP_GET) {
++            GstRTSPMessage *response;
++            GstRTSPStatusCode code;
++
++            watch->conn->tstate = TUNNEL_STATE_GET;
++
++            if (watch->funcs.tunnel_start)
++              code = watch->funcs.tunnel_start (watch, watch->user_data);
++            else
++              code = GST_RTSP_STS_OK;
++
++            /* queue the response */
++            response = gen_tunnel_reply (watch->conn, code, &watch->message);
++            gst_rtsp_watch_send_message (watch, response, NULL);
++            gst_rtsp_message_free (response);
++            goto read_done;
++          } else if (watch->conn->tstate == TUNNEL_STATE_NONE &&
++              watch->message.type_data.request.method == GST_RTSP_POST) {
++            watch->conn->tstate = TUNNEL_STATE_POST;
++
++            /* in the callback the connection should be tunneled with the
++             * GET connection */
++            if (watch->funcs.tunnel_complete)
++              watch->funcs.tunnel_complete (watch, watch->user_data);
++            goto read_done;
++          }
++        }
++      }
++
++      if (!watch->conn->manual_http) {
++        /* if manual HTTP support is not enabled, then restore the message to
++         * what it would have looked like without the support for parsing HTTP
++         * messages being present */
++        if (watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
++          watch->message.type = GST_RTSP_MESSAGE_REQUEST;
++          watch->message.type_data.request.method = GST_RTSP_INVALID;
++          if (watch->message.type_data.request.version != GST_RTSP_VERSION_1_0)
++            watch->message.type_data.request.version = GST_RTSP_VERSION_INVALID;
++          res = GST_RTSP_EPARSE;
++        } else if (watch->message.type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
++          watch->message.type = GST_RTSP_MESSAGE_RESPONSE;
++          if (watch->message.type_data.response.version != GST_RTSP_VERSION_1_0)
++            watch->message.type_data.response.version =
++                GST_RTSP_VERSION_INVALID;
++          res = GST_RTSP_EPARSE;
++        }
++      }
++
++      if (G_LIKELY (res == GST_RTSP_OK)) {
++        if (watch->funcs.message_received)
++          watch->funcs.message_received (watch, &watch->message,
++              watch->user_data);
++      } else {
++        if (watch->funcs.error_full)
++          GST_RTSP_CHECK (watch->funcs.error_full (watch, res, &watch->message,
++                  0, watch->user_data), error);
++        else
++          goto error;
++      }
++
++    read_done:
++      gst_rtsp_message_unset (&watch->message);
++      build_reset (&watch->builder);
++    } while (FALSE);
++  }
++
++  if (watch->writefd.revents & WRITE_COND) {
++    g_mutex_lock (watch->mutex);
++    do {
++      if (watch->write_data == NULL) {
++        GstRTSPRec *rec;
++
++        /* get a new message from the queue */
++        rec = g_queue_pop_tail (watch->messages);
++        if (rec == NULL)
++          goto done;
++
++        watch->write_off = 0;
++        watch->write_data = rec->data;
++        watch->write_size = rec->size;
++        watch->write_id = rec->id;
++
++        g_slice_free (GstRTSPRec, rec);
++      }
++
++      res = write_bytes (watch->writefd.fd, watch->write_data,
++          &watch->write_off, watch->write_size);
++      g_mutex_unlock (watch->mutex);
++      if (res == GST_RTSP_EINTR)
++        goto write_blocked;
++      else if (G_LIKELY (res == GST_RTSP_OK)) {
++        if (watch->funcs.message_sent)
++          watch->funcs.message_sent (watch, watch->write_id, watch->user_data);
++      } else {
++        if (watch->funcs.error_full)
++          GST_RTSP_CHECK (watch->funcs.error_full (watch, res, NULL,
++                  watch->write_id, watch->user_data), error);
++        else
++          goto error;
++      }
++      g_mutex_lock (watch->mutex);
++
++      g_free (watch->write_data);
++      watch->write_data = NULL;
++    } while (TRUE);
++
++  done:
++    if (watch->write_added) {
++      g_source_remove_poll ((GSource *) watch, &watch->writefd);
++      watch->write_added = FALSE;
++      watch->writefd.revents = 0;
++    }
++
++    g_mutex_unlock (watch->mutex);
++  }
++
++write_blocked:
++  return TRUE;
++
++  /* ERRORS */
++eof:
++  {
++    if (watch->funcs.closed)
++      watch->funcs.closed (watch, watch->user_data);
++    return FALSE;
++  }
++error:
++  {
++    if (watch->funcs.error)
++      watch->funcs.error (watch, res, watch->user_data);
++    return FALSE;
++  }
++}
++
++static void
++gst_rtsp_rec_free (gpointer data)
++{
++  GstRTSPRec *rec = data;
++
++  g_free (rec->data);
++  g_slice_free (GstRTSPRec, rec);
++}
++
++static void
++gst_rtsp_source_finalize (GSource * source)
++{
++  GstRTSPWatch *watch = (GstRTSPWatch *) source;
++
++  build_reset (&watch->builder);
++  gst_rtsp_message_unset (&watch->message);
++
++  g_queue_foreach (watch->messages, (GFunc) gst_rtsp_rec_free, NULL);
++  g_queue_free (watch->messages);
++  watch->messages = NULL;
++
++  g_mutex_free (watch->mutex);
++
++  g_free (watch->write_data);
++
++  if (watch->notify)
++    watch->notify (watch->user_data);
++}
++
++static GSourceFuncs gst_rtsp_source_funcs = {
++  gst_rtsp_source_prepare,
++  gst_rtsp_source_check,
++  gst_rtsp_source_dispatch,
++  gst_rtsp_source_finalize,
++  NULL,
++  NULL
++};
++
++/**
++ * gst_rtsp_watch_new:
++ * @conn: a #GstRTSPConnection
++ * @funcs: watch functions
++ * @user_data: user data to pass to @funcs
++ * @notify: notify when @user_data is not referenced anymore
++ *
++ * Create a watch object for @conn. The functions provided in @funcs will be
++ * called with @user_data when activity happened on the watch.
++ *
++ * The new watch is usually created so that it can be attached to a
++ * maincontext with gst_rtsp_watch_attach(). 
++ *
++ * @conn must exist for the entire lifetime of the watch.
++ *
++ * Returns: a #GstRTSPWatch that can be used for asynchronous RTSP
++ * communication. Free with gst_rtsp_watch_unref () after usage.
++ *
++ * Since: 0.10.23
++ */
++GstRTSPWatch *
++gst_rtsp_watch_new (GstRTSPConnection * conn,
++    GstRTSPWatchFuncs * funcs, gpointer user_data, GDestroyNotify notify)
++{
++  GstRTSPWatch *result;
++
++  g_return_val_if_fail (conn != NULL, NULL);
++  g_return_val_if_fail (funcs != NULL, NULL);
++  g_return_val_if_fail (conn->readfd != NULL, NULL);
++  g_return_val_if_fail (conn->writefd != NULL, NULL);
++
++  result = (GstRTSPWatch *) g_source_new (&gst_rtsp_source_funcs,
++      sizeof (GstRTSPWatch));
++
++  result->conn = conn;
++  result->builder.state = STATE_START;
++
++  result->mutex = g_mutex_new ();
++  result->messages = g_queue_new ();
++
++  result->readfd.fd = -1;
++  result->writefd.fd = -1;
++
++  gst_rtsp_watch_reset (result);
++
++  result->funcs = *funcs;
++  result->user_data = user_data;
++  result->notify = notify;
++
++  /* only add the read fd, the write fd is only added when we have data
++   * to send. */
++  g_source_add_poll ((GSource *) result, &result->readfd);
++
++  return result;
++}
++
++/**
++ * gst_rtsp_watch_reset:
++ * @watch: a #GstRTSPWatch
++ *
++ * Reset @watch, this is usually called after gst_rtsp_connection_do_tunnel()
++ * when the file descriptors of the connection might have changed.
++ *
++ * Since: 0.10.23
++ */
++void
++gst_rtsp_watch_reset (GstRTSPWatch * watch)
++{
++  if (watch->readfd.fd != -1)
++    g_source_remove_poll ((GSource *) watch, &watch->readfd);
++  if (watch->writefd.fd != -1)
++    g_source_remove_poll ((GSource *) watch, &watch->writefd);
++
++  watch->readfd.fd = watch->conn->readfd->fd;
++  watch->readfd.events = READ_COND;
++  watch->readfd.revents = 0;
++
++  watch->writefd.fd = watch->conn->writefd->fd;
++  watch->writefd.events = WRITE_COND;
++  watch->writefd.revents = 0;
++  watch->write_added = FALSE;
++
++  g_source_add_poll ((GSource *) watch, &watch->readfd);
++}
++
++/**
++ * gst_rtsp_watch_attach:
++ * @watch: a #GstRTSPWatch
++ * @context: a GMainContext (if NULL, the default context will be used)
++ *
++ * Adds a #GstRTSPWatch to a context so that it will be executed within that context.
++ *
++ * Returns: the ID (greater than 0) for the watch within the GMainContext. 
++ *
++ * Since: 0.10.23
++ */
++guint
++gst_rtsp_watch_attach (GstRTSPWatch * watch, GMainContext * context)
++{
++  g_return_val_if_fail (watch != NULL, 0);
++
++  return g_source_attach ((GSource *) watch, context);
++}
++
++/**
++ * gst_rtsp_watch_unref:
++ * @watch: a #GstRTSPWatch
++ *
++ * Decreases the reference count of @watch by one. If the resulting reference
++ * count is zero the watch and associated memory will be destroyed.
++ *
++ * Since: 0.10.23
++ */
++void
++gst_rtsp_watch_unref (GstRTSPWatch * watch)
++{
++  g_return_if_fail (watch != NULL);
++
++  g_source_unref ((GSource *) watch);
++}
++
++/**
++ * gst_rtsp_watch_write_data:
++ * @watch: a #GstRTSPWatch
++ * @data: the data to queue
++ * @size: the size of @data
++ * @id: location for a message ID or %NULL
++ *
++ * Write @data using the connection of the @watch. If it cannot be sent
++ * immediately, it will be queued for transmission in @watch. The contents of
++ * @message will then be serialized and transmitted when the connection of the
++ * @watch becomes writable. In case the @message is queued, the ID returned in
++ * @id will be non-zero and used as the ID argument in the message_sent
++ * callback.
++ *
++ * This function will take ownership of @data and g_free() it after use.
++ *
++ * Returns: #GST_RTSP_OK on success.
++ *
++ * Since: 0.10.25
++ */
++GstRTSPResult
++gst_rtsp_watch_write_data (GstRTSPWatch * watch, const guint8 * data,
++    guint size, guint * id)
++{
++  GstRTSPResult res;
++  GstRTSPRec *rec;
++  guint off = 0;
++
++  g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (size != 0, GST_RTSP_EINVAL);
++
++  g_mutex_lock (watch->mutex);
++
++  if (watch->messages->length == 0) {
++    res = write_bytes (watch->writefd.fd, data, &off, size);
++    if (res != GST_RTSP_EINTR) {
++      if (id != NULL)
++        *id = 0;
++      g_free ((gpointer) data);
++      goto done;
++    }
++  }
++
++  /* make a record with the data and id */
++  rec = g_slice_new (GstRTSPRec);
++  if (off == 0) {
++    rec->data = (guint8 *) data;
++    rec->size = size;
++  } else {
++    rec->data = g_memdup (data + off, size - off);
++    rec->size = size - off;
++    g_free ((gpointer) data);
++  }
++
++  do {
++    /* make sure rec->id is never 0 */
++    rec->id = ++watch->id;
++  } while (G_UNLIKELY (rec->id == 0));
++
++  /* add the record to a queue. FIXME we would like to have an upper limit here */
++  g_queue_push_head (watch->messages, rec);
++
++  /* make sure the main context will now also check for writability on the
++   * socket */
++  if (!watch->write_added) {
++    g_source_add_poll ((GSource *) watch, &watch->writefd);
++    watch->write_added = TRUE;
++  }
++
++  if (id != NULL)
++    *id = rec->id;
++  res = GST_RTSP_OK;
++
++done:
++  g_mutex_unlock (watch->mutex);
++  return res;
++}
++
++/**
++ * gst_rtsp_watch_send_message:
++ * @watch: a #GstRTSPWatch
++ * @message: a #GstRTSPMessage
++ * @id: location for a message ID or %NULL
++ *
++ * Send a @message using the connection of the @watch. If it cannot be sent
++ * immediately, it will be queued for transmission in @watch. The contents of
++ * @message will then be serialized and transmitted when the connection of the
++ * @watch becomes writable. In case the @message is queued, the ID returned in
++ * @id will be non-zero and used as the ID argument in the message_sent
++ * callback.
++ *
++ * Returns: #GST_RTSP_OK on success.
++ *
++ * Since: 0.10.25
++ */
++GstRTSPResult
++gst_rtsp_watch_send_message (GstRTSPWatch * watch, GstRTSPMessage * message,
++    guint * id)
++{
++  GString *str;
++  guint size;
++
++  g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
++
++  /* make a record with the message as a string and id */
++  str = message_to_string (watch->conn, message);
++  size = str->len;
++  return gst_rtsp_watch_write_data (watch,
++      (guint8 *) g_string_free (str, FALSE), size, id);
++}
++
++/**
++ * gst_rtsp_watch_queue_data:
++ * @watch: a #GstRTSPWatch
++ * @data: the data to queue
++ * @size: the size of @data
++ *
++ * Queue @data for transmission in @watch. It will be transmitted when the
++ * connection of the @watch becomes writable.
++ *
++ * This function will take ownership of @data and g_free() it after use.
++ *
++ * The return value of this function will be used as the id argument in the
++ * message_sent callback.
++ *
++ * Deprecated: Use gst_rtsp_watch_write_data()
++ *
++ * Returns: an id.
++ *
++ * Since: 0.10.24
++ */
++#ifndef GST_REMOVE_DEPRECATED
++guint
++gst_rtsp_watch_queue_data (GstRTSPWatch * watch, const guint8 * data,
++    guint size)
++{
++  GstRTSPRec *rec;
++
++  g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (size != 0, GST_RTSP_EINVAL);
++
++  g_mutex_lock (watch->mutex);
++
++  /* make a record with the data and id */
++  rec = g_slice_new (GstRTSPRec);
++  rec->data = (guint8 *) data;
++  rec->size = size;
++  do {
++    /* make sure rec->id is never 0 */
++    rec->id = ++watch->id;
++  } while (G_UNLIKELY (rec->id == 0));
++
++  /* add the record to a queue. FIXME we would like to have an upper limit here */
++  g_queue_push_head (watch->messages, rec);
++
++  /* make sure the main context will now also check for writability on the
++   * socket */
++  if (!watch->write_added) {
++    g_source_add_poll ((GSource *) watch, &watch->writefd);
++    watch->write_added = TRUE;
++  }
++
++  g_mutex_unlock (watch->mutex);
++  return rec->id;
++}
++#endif /* GST_REMOVE_DEPRECATED */
++
++/**
++ * gst_rtsp_watch_queue_message:
++ * @watch: a #GstRTSPWatch
++ * @message: a #GstRTSPMessage
++ *
++ * Queue a @message for transmission in @watch. The contents of this
++ * message will be serialized and transmitted when the connection of the
++ * @watch becomes writable.
++ *
++ * The return value of this function will be used as the id argument in the
++ * message_sent callback.
++ *
++ * Deprecated: Use gst_rtsp_watch_send_message()
++ *
++ * Returns: an id.
++ *
++ * Since: 0.10.23
++ */
++#ifndef GST_REMOVE_DEPRECATED
++guint
++gst_rtsp_watch_queue_message (GstRTSPWatch * watch, GstRTSPMessage * message)
++{
++  GString *str;
++  guint size;
++
++  g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
++  g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
++
++  /* make a record with the message as a string and id */
++  str = message_to_string (watch->conn, message);
++  size = str->len;
++  return gst_rtsp_watch_queue_data (watch,
++      (guint8 *) g_string_free (str, FALSE), size);
++}
++#endif /* GST_REMOVE_DEPRECATED */
index 0000000,0000000..dfa2c50
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,85 @@@
++#include "rtsp-marshal.h"
++
++#include      <glib-object.h>
++
++
++#ifdef G_ENABLE_DEBUG
++#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
++#define g_marshal_value_peek_char(v)     g_value_get_char (v)
++#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
++#define g_marshal_value_peek_int(v)      g_value_get_int (v)
++#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
++#define g_marshal_value_peek_long(v)     g_value_get_long (v)
++#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
++#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
++#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
++#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
++#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
++#define g_marshal_value_peek_float(v)    g_value_get_float (v)
++#define g_marshal_value_peek_double(v)   g_value_get_double (v)
++#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
++#define g_marshal_value_peek_param(v)    g_value_get_param (v)
++#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
++#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
++#define g_marshal_value_peek_object(v)   g_value_get_object (v)
++#else /* !G_ENABLE_DEBUG */
++/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
++ *          Do not access GValues directly in your code. Instead, use the
++ *          g_value_get_*() functions
++ */
++#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
++#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
++#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
++#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
++#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
++#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
++#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
++#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
++#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
++#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
++#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
++#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
++#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
++#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
++#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
++#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
++#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
++#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
++#endif /* !G_ENABLE_DEBUG */
++
++
++/* ENUM:POINTER,POINTER (rtsp-marshal.list:1) */
++void
++gst_rtsp_marshal_ENUM__POINTER_POINTER (GClosure * closure,
++    GValue * return_value G_GNUC_UNUSED,
++    guint n_param_values,
++    const GValue * param_values,
++    gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
++{
++  typedef gint (*GMarshalFunc_ENUM__POINTER_POINTER) (gpointer data1,
++      gpointer arg_1, gpointer arg_2, gpointer data2);
++  register GMarshalFunc_ENUM__POINTER_POINTER callback;
++  register GCClosure *cc = (GCClosure *) closure;
++  register gpointer data1, data2;
++  gint v_return;
++
++  g_return_if_fail (return_value != NULL);
++  g_return_if_fail (n_param_values == 3);
++
++  if (G_CCLOSURE_SWAP_DATA (closure)) {
++    data1 = closure->data;
++    data2 = g_value_peek_pointer (param_values + 0);
++  } else {
++    data1 = g_value_peek_pointer (param_values + 0);
++    data2 = closure->data;
++  }
++  callback =
++      (GMarshalFunc_ENUM__POINTER_POINTER) (marshal_data ? marshal_data :
++      cc->callback);
++
++  v_return = callback (data1,
++      g_marshal_value_peek_pointer (param_values + 1),
++      g_marshal_value_peek_pointer (param_values + 2), data2);
++
++  g_value_set_enum (return_value, v_return);
++}
index 0000000,0000000..0106232
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++
++#ifndef __gst_rtsp_marshal_MARSHAL_H__
++#define __gst_rtsp_marshal_MARSHAL_H__
++
++#include      <glib-object.h>
++
++G_BEGIN_DECLS
++
++/* ENUM:POINTER,POINTER (rtsp-marshal.list:1) */
++extern void gst_rtsp_marshal_ENUM__POINTER_POINTER (GClosure     *closure,
++                                                    GValue       *return_value,
++                                                    guint         n_param_values,
++                                                    const GValue *param_values,
++                                                    gpointer      invocation_hint,
++                                                    gpointer      marshal_data);
++
++G_END_DECLS
++
++#endif /* __gst_rtsp_marshal_MARSHAL_H__ */
++
index 0000000,0000000..bc16338
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,73 @@@
++commit bf5ef87699b8ef602548eec131312d7a733e278e
++Author: Josep Torra <n770galaxy@gmail.com>
++Date:   Tue Apr 14 18:03:09 2009 +0200
++
++    Added RTSP headers related to Windows Media extension.
++
++diff --git a/gst-libs/gst/rtsp/gstrtspdefs.c b/gst-libs/gst/rtsp/gstrtspdefs.c
++index 0ab2b95..8b086e5 100644
++--- a/gst-libs/gst/rtsp/gstrtspdefs.c
+++++ b/gst-libs/gst/rtsp/gstrtspdefs.c
++@@ -164,6 +164,27 @@ static const gchar *rtsp_headers[] = {
++   "ETag",                       /* ETag */
++   "If-Match",                   /* If-Match */
++ 
+++  /* WM extensions [MS-RTSP] */
+++  "Accept-Charset",             /* Accept-Charset */
+++  "Supported",                  /* Supported */
+++  "Vary",                       /* Vary */
+++  "X-Accelerate-Streaming",     /* X-Accelerate-Streaming */
+++  "X-Accept-Authentication",    /* X-Accept-Authentication */
+++  "X-Accept-Proxy-Authentication",      /* X-Accept-Proxy-Authentication */
+++  "X-Broadcast-Id",             /* X-Broadcast-Id */
+++  "X-Burst-Streaming",          /* X-Burst-Streaming */
+++  "X-Notice",                   /* X-Notice */
+++  "X-Player-Lag-Time",          /* X-Player-Lag-Time */
+++  "X-Playlist",                 /* X-Playlist */
+++  "X-Playlist-Change-Notice",   /* X-Playlist-Change-Notice */
+++  "X-Playlist-Gen-Id",          /* X-Playlist-Gen-Id */
+++  "X-Playlist-Seek-Id",         /* X-Playlist-Seek-Id */
+++  "X-Proxy-Client-Agent",       /* X-Proxy-Client-Agent */
+++  "X-Proxy-Client-Verb",        /* X-Proxy-Client-Verb */
+++  "X-Receding-PlaylistChange",  /* X-Receding-PlaylistChange */
+++  "X-RTP-Info",                 /* X-RTP-Info */
+++  "X-StartupProfile",           /* X-StartupProfile */
+++
++   NULL
++ };
++ 
++diff --git a/gst-libs/gst/rtsp/gstrtspdefs.h b/gst-libs/gst/rtsp/gstrtspdefs.h
++index dd4b531..ae3b105 100644
++--- a/gst-libs/gst/rtsp/gstrtspdefs.h
+++++ b/gst-libs/gst/rtsp/gstrtspdefs.h
++@@ -287,7 +287,29 @@ typedef enum {
++ 
++   /* Since 0.10.23 */
++   GST_RTSP_HDR_ETAG,                /* ETag */
++-  GST_RTSP_HDR_IF_MATCH             /* If-Match */
+++  GST_RTSP_HDR_IF_MATCH,            /* If-Match */
+++
+++  /* WM extensions [MS-RTSP] */
+++  GST_RTSP_HDR_ACCEPT_CHARSET,      /* Accept-Charset */
+++  GST_RTSP_HDR_SUPPORTED,           /* Supported */
+++  GST_RTSP_HDR_VARY,                /* Vary */
+++  GST_RTSP_HDR_X_ACCELERATE_STREAMING,    /* X-Accelerate-Streaming */
+++  GST_RTSP_HDR_X_ACCEPT_AUTHENT,    /* X-Accept-Authentication */
+++  GST_RTSP_HDR_X_ACCEPT_PROXY_AUTHENT,    /* X-Accept-Proxy-Authentication */
+++  GST_RTSP_HDR_X_BROADCAST_ID,      /* X-Broadcast-Id */
+++  GST_RTSP_HDR_X_BURST_STREAMING,   /* X-Burst-Streaming */
+++  GST_RTSP_HDR_X_NOTICE,            /* X-Notice */
+++  GST_RTSP_HDR_X_PLAYER_LAG_TIME,   /* X-Player-Lag-Time */
+++  GST_RTSP_HDR_X_PLAYLIST,          /* X-Playlist */
+++  GST_RTSP_HDR_X_PLAYLIST_CHANGE_NOTICE,  /* X-Playlist-Change-Notice */
+++  GST_RTSP_HDR_X_PLAYLIST_GEN_ID,   /* X-Playlist-Gen-Id */
+++  GST_RTSP_HDR_X_PLAYLIST_SEEK_ID,  /* X-Playlist-Seek-Id */
+++  GST_RTSP_HDR_X_PROXY_CLIENT_AGENT,      /* X-Proxy-Client-Agent */
+++  GST_RTSP_HDR_X_PROXY_CLIENT_VERB, /* X-Proxy-Client-Verb */
+++  GST_RTSP_HDR_X_RECEDING_PLAYLISTCHANGE, /* X-Receding-PlaylistChange */
+++  GST_RTSP_HDR_X_RTP_INFO,          /* X-RTP-Info */
+++  GST_RTSP_HDR_X_STARTUPPROFILE     /* X-StartupProfile */
+++
++ } GstRTSPHeaderField;
++ 
++ typedef enum {
index 0000000,0000000..38ef9a1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,82 @@@
++/* GStreamer
++ * Copyright (C) <2011> Wim Taymans <wim.taymans@gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __GST_META_VIDEO_H__
++#define __GST_META_VIDEO_H__
++
++#include <gst/gst.h>
++
++#include <gst/video/video.h>
++
++G_BEGIN_DECLS
++
++#define GST_META_API_VIDEO   "GstMetaVideo"
++#define GST_META_INFO_VIDEO  (gst_meta_video_get_info())
++
++typedef struct _GstMetaVideo GstMetaVideo;
++
++/**
++ * GstMetaVideo:
++ * @meta: parent #GstMeta
++ * @flags: additional video flags
++ * @n_planes: the number of planes in the image
++ * @offset: array of offsets for the planes
++ * @stride: array of strides for the planes
++ * @map: map the memory of a plane
++ * @unmap: unmap the memory of a plane
++ *
++ * Extra buffer metadata describing image properties
++ */
++struct _GstMetaVideo {
++  GstMeta            meta;
++
++  GstBuffer         *buffer;
++
++  GstVideoFlags      flags;
++  GstVideoFormat     format;
++  guint              width;
++  guint              height;
++
++  guint              n_planes;
++  gsize              offset[GST_VIDEO_MAX_PLANES];
++  gint               stride[GST_VIDEO_MAX_PLANES];
++
++  gpointer (*map)    (GstMetaVideo *meta, guint plane, gint *stride,
++                      GstMapFlags flags);
++  gboolean (*unmap)  (GstMetaVideo *meta, guint plane, gpointer data);
++};
++
++const GstMetaInfo * gst_meta_video_get_info (void);
++
++#define gst_buffer_get_meta_video(b) ((GstMetaVideo*)gst_buffer_get_meta((b),GST_META_INFO_VIDEO))
++GstMetaVideo * gst_buffer_add_meta_video       (GstBuffer *buffer, GstVideoFlags flags,
++                                                GstVideoFormat format, guint width, guint height);
++GstMetaVideo * gst_buffer_add_meta_video_full  (GstBuffer *buffer, GstVideoFlags flags,
++                                                GstVideoFormat format, guint width, guint height,
++                                                guint n_planes, gsize offset[GST_VIDEO_MAX_PLANES],
++                                                gint stride[GST_VIDEO_MAX_PLANES]);
++
++gpointer       gst_meta_video_map        (GstMetaVideo *meta, guint plane, gint *stride,
++                                          GstMapFlags flags);
++gboolean       gst_meta_video_unmap      (GstMetaVideo *meta, guint plane, gpointer data);
++
++
++G_END_DECLS
++
++#endif /* __GST_META_VIDEO_H__ */
@@@ -230,8 -230,11 +230,8 @@@ struct _StreamGrou
  #define DEFAULT_FLAGS              0
  
  #define DEFAULT_RAW_CAPS                      \
 -  "video/x-raw-yuv; "                         \
 -  "video/x-raw-rgb; "                         \
 -  "video/x-raw-gray; "                                \
 -  "audio/x-raw-int; "                         \
 -  "audio/x-raw-float; "                               \
 +  "video/x-raw; "                             \
 +  "audio/x-raw; "                             \
    "text/plain; "                              \
    "text/x-pango-markup; "                     \
    "video/x-dvd-subpicture; "                  \
@@@ -341,7 -344,7 +341,7 @@@ gst_encode_bin_class_init (GstEncodeBin
     * to %GST_STATE_PAUSED or higher.
     */
    g_object_class_install_property (gobject_klass, PROP_PROFILE,
 -      gst_param_spec_mini_object ("profile", "Profile",
 +      g_param_spec_object ("profile", "Profile",
            "The GstEncodingProfile to use", GST_TYPE_ENCODING_PROFILE,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
  
    gstelement_klass->change_state =
        GST_DEBUG_FUNCPTR (gst_encode_bin_change_state);
 -  gstelement_klass->request_new_pad_full =
 +  gstelement_klass->request_new_pad =
        GST_DEBUG_FUNCPTR (gst_encode_bin_request_new_pad);
    gstelement_klass->release_pad =
        GST_DEBUG_FUNCPTR (gst_encode_bin_release_pad);
@@@ -480,8 -483,10 +480,8 @@@ gst_encode_bin_init (GstEncodeBin * enc
        gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER,
        GST_RANK_MARGINAL);
  
 -  encode_bin->raw_video_caps =
 -      gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb;video/x-raw-gray");
 -  encode_bin->raw_audio_caps =
 -      gst_caps_from_string ("audio/x-raw-int;audio/x-raw-float");
 +  encode_bin->raw_video_caps = gst_caps_from_string ("video/x-raw");
 +  encode_bin->raw_audio_caps = gst_caps_from_string ("audio/x-raw");
    /* encode_bin->raw_text_caps = */
    /*     gst_caps_from_string ("text/plain;text/x-pango-markup"); */
  
@@@ -507,7 -512,7 +507,7 @@@ gst_encode_bin_set_property (GObject * 
    switch (prop_id) {
      case PROP_PROFILE:
        gst_encode_bin_set_profile (ebin,
 -          (GstEncodingProfile *) gst_value_get_mini_object (value));
 +          (GstEncodingProfile *) g_value_get_object (value));
        break;
      case PROP_QUEUE_BUFFERS_MAX:
        ebin->queue_buffers_max = g_value_get_uint (value);
@@@ -541,7 -546,7 +541,7 @@@ gst_encode_bin_get_property (GObject * 
  
    switch (prop_id) {
      case PROP_PROFILE:
 -      gst_value_set_mini_object (value, (GstMiniObject *) ebin->profile);
 +      g_value_set_object (value, (GObject *) ebin->profile);
        break;
      case PROP_QUEUE_BUFFERS_MAX:
        g_value_set_uint (value, ebin->queue_buffers_max);
@@@ -818,12 -823,13 +818,12 @@@ _create_element_and_set_preset (GstElem
  {
    GstElement *res = NULL;
  
 -  GST_DEBUG ("Creating element from factory %s",
 -      GST_PLUGIN_FEATURE_NAME (factory));
 +  GST_DEBUG ("Creating element from factory %s", GST_OBJECT_NAME (factory));
    res = gst_element_factory_create (factory, name);
    if (preset && GST_IS_PRESET (res) &&
        !gst_preset_load_preset (GST_PRESET (res), preset)) {
      GST_WARNING ("Couldn't set preset [%s] on element [%s]",
 -        preset, GST_PLUGIN_FEATURE_NAME (factory));
 +        preset, GST_OBJECT_NAME (factory));
      gst_object_unref (res);
      res = NULL;
    }
@@@ -876,7 -882,7 +876,7 @@@ beach
  
  static GstPad *
  local_element_request_pad (GstElement * element, GstPadTemplate * templ,
 -    const gchar * name)
 +    const gchar * name, const GstCaps * caps)
  {
    GstPad *newpad = NULL;
    GstElementClass *oclass;
    oclass = GST_ELEMENT_GET_CLASS (element);
  
    if (oclass->request_new_pad)
 -    newpad = (oclass->request_new_pad) (element, templ, name);
 +    newpad = (oclass->request_new_pad) (element, templ, name, caps);
  
    if (newpad)
      gst_object_ref (newpad);
@@@ -925,7 -931,7 +925,7 @@@ gst_element_get_pad_from_template (GstE
  /* FIXME : Improve algorithm for finding compatible muxer sink pad */
  static inline GstPad *
  get_compatible_muxer_sink_pad (GstEncodeBin * ebin, GstElement * encoder,
 -    const GstCaps * sinkcaps)
 +    GstCaps * sinkcaps)
  {
    GstPad *sinkpad;
    GstPadTemplate *srctempl = NULL;
  
      gst_object_unref (srcpad);
      sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
 +    gst_object_unref (srctempl);
    } else {
      srctempl =
          gst_pad_template_new ("whatever", GST_PAD_SRC, GST_PAD_ALWAYS,
 -        gst_caps_copy (sinkcaps));
 +        sinkcaps);
      g_assert (srctempl != NULL);
      sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
      g_object_unref (srctempl);
@@@ -971,12 -976,10 +971,12 @@@ static gboolea
  _has_class (GstElement * element, const gchar * classname)
  {
    GstElementClass *klass;
 +  const gchar *value;
  
    klass = GST_ELEMENT_GET_CLASS (element);
 +  value = gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS);
  
 -  return strstr (klass->details.klass, classname) != NULL;
 +  return strstr (value, classname) != NULL;
  }
  
  /* FIXME : Add handling of streams that don't need encoding  */
@@@ -995,7 -998,8 +995,7 @@@ _create_stream_group (GstEncodeBin * eb
    /* Element we will link to the encoder */
    GstElement *last = NULL;
    GList *tmp, *tosync = NULL;
 -  const GstCaps *format;
 -  const GstCaps *restriction;
 +  GstCaps *format, *restriction;
    const gchar *missing_element_name;
  
    format = gst_encoding_profile_get_format (sprof);
     * If we have no muxer or
     * if the muxer isn't a formatter and doesn't implement the tagsetter interface
     */
 -  if (!ebin->muxer
 -      || (!gst_element_implements_interface (ebin->muxer, GST_TYPE_TAG_SETTER)
 +  if (!ebin->muxer || (!GST_IS_TAG_SETTER (ebin->muxer)
            || !_has_class (ebin->muxer, "Formatter"))) {
      sgroup->formatter = _get_formatter (ebin, sprof);
      if (sgroup->formatter) {
  
    /* Path 1 : Already-encoded data */
    sinkpad =
 -      local_element_request_pad (sgroup->combiner, NULL, "passthroughsink");
 +      local_element_request_pad (sgroup->combiner, NULL, "passthroughsink",
 +      NULL);
    if (G_UNLIKELY (sinkpad == NULL))
      goto no_combiner_sinkpad;
  
  
      /* Check if stream format is compatible */
      srcpad = gst_element_get_static_pad (sgroup->smartencoder, "src");
 -    tmpcaps = gst_pad_get_caps (srcpad);
 +    tmpcaps = gst_pad_get_caps (srcpad, NULL);
      if (!gst_caps_can_intersect (tmpcaps, format)) {
        GST_DEBUG ("We don't have a smart encoder for the stream format");
        gst_object_unref (sgroup->smartencoder);
      g_object_unref (srcpad);
    }
  
 -  srcpad = local_element_request_pad (sgroup->splitter, NULL, "passthroughsrc");
 +  srcpad =
 +      local_element_request_pad (sgroup->splitter, NULL, "passthroughsrc",
 +      NULL);
    if (G_UNLIKELY (srcpad == NULL))
      goto no_splitter_srcpad;
  
    gst_bin_add ((GstBin *) ebin, sgroup->encoder);
    tosync = g_list_append (tosync, sgroup->encoder);
  
 -  sinkpad = local_element_request_pad (sgroup->combiner, NULL, "encodingsink");
 +  sinkpad =
 +      local_element_request_pad (sgroup->combiner, NULL, "encodingsink", NULL);
    if (G_UNLIKELY (sinkpad == NULL))
      goto no_combiner_sinkpad;
    srcpad = gst_element_get_static_pad (sgroup->encoder, "src");
    /* FIXME : Once we have properties for specific converters, use those */
    if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
      const gboolean native_video =
--        ! !(ebin->flags & GST_ENC_FLAG_NO_VIDEO_CONVERSION);
++        !!(ebin->flags & GST_ENC_FLAG_NO_VIDEO_CONVERSION);
      GstElement *cspace = NULL, *scale, *vrate, *cspace2 = NULL;
  
      GST_LOG ("Adding conversion elements for video stream");
  
      if (!native_video) {
 -      cspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
 +      cspace = gst_element_factory_make ("videoconvert", NULL);
        scale = gst_element_factory_make ("videoscale", NULL);
        if (!scale) {
          missing_element_name = "videoscale";
        }
        /* 4-tap scaling and black borders */
        g_object_set (scale, "method", 2, "add-borders", TRUE, NULL);
 -      cspace2 = gst_element_factory_make ("ffmpegcolorspace", NULL);
 +      cspace2 = gst_element_factory_make ("videoconvert", NULL);
  
        if (!cspace || !cspace2) {
 -        missing_element_name = "ffmpegcolorspace";
 +        missing_element_name = "videoconvert";
          goto missing_element;
        }
  
  
    /* Link to stream splitter */
    sinkpad = gst_element_get_static_pad (last, "sink");
 -  srcpad = local_element_request_pad (sgroup->splitter, NULL, "encodingsrc");
 +  srcpad =
 +      local_element_request_pad (sgroup->splitter, NULL, "encodingsrc", NULL);
    if (G_UNLIKELY (srcpad == NULL))
      goto no_splitter_srcpad;
    if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
  
    ebin->streams = g_list_prepend (ebin->streams, sgroup);
  
 +  if (format)
 +    gst_caps_unref (format);
 +  if (restriction)
 +    gst_caps_unref (restriction);
 +
    return sgroup;
  
  splitter_encoding_failure:
@@@ -1479,26 -1474,64 +1479,68 @@@ converter_link_failure
  
  cleanup:
    /* FIXME : Actually properly cleanup everything */
 +  if (format)
 +    gst_caps_unref (format);
 +  if (restriction)
 +    gst_caps_unref (restriction);
    g_slice_free (StreamGroup, sgroup);
    return NULL;
  }
  
  static gboolean
- _factory_can_sink_caps (GstElementFactory * factory, const GstCaps * caps)
+ _gst_caps_match_foreach (GQuark field_id, const GValue * value, gpointer data)
+ {
+   GstStructure *structure = data;
+   const GValue *other_value = gst_structure_id_get_value (structure, field_id);
+   if (G_UNLIKELY (other_value == NULL))
+     return FALSE;
+   if (gst_value_compare (value, other_value) == GST_VALUE_EQUAL) {
+     return TRUE;
+   }
+   return FALSE;
+ }
+ /*
+  * checks that there is at least one structure on caps_a that has
+  * all its fields exactly the same as one structure on caps_b
+  */
+ static gboolean
+ _gst_caps_match (const GstCaps * caps_a, const GstCaps * caps_b)
+ {
+   gint i, j;
+   gboolean res = FALSE;
+   for (i = 0; i < gst_caps_get_size (caps_a); i++) {
+     GstStructure *structure_a = gst_caps_get_structure (caps_a, i);
+     for (j = 0; j < gst_caps_get_size (caps_b); j++) {
+       GstStructure *structure_b = gst_caps_get_structure (caps_b, j);
+       res = gst_structure_foreach (structure_a, _gst_caps_match_foreach,
+           structure_b);
+       if (res)
+         goto end;
+     }
+   }
+ end:
+   return res;
+ }
+ static gboolean
+ _factory_can_handle_caps (GstElementFactory * factory, const GstCaps * caps,
+     GstPadDirection dir, gboolean exact)
  {
    GList *templates = factory->staticpadtemplates;
  
    while (templates) {
      GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
  
-     if (template->direction == GST_PAD_SINK) {
+     if (template->direction == dir) {
        GstCaps *tmp = gst_static_caps_get (&template->static_caps);
  
-       if (gst_caps_can_intersect (tmp, caps)) {
+       if ((exact && _gst_caps_match (caps, tmp)) ||
+           (!exact && gst_caps_can_intersect (tmp, caps))) {
          gst_caps_unref (tmp);
          return TRUE;
        }
@@@ -1536,7 -1569,7 +1578,7 @@@ _get_formatter (GstEncodeBin * ebin, Gs
      formatterfact = (GstElementFactory *) tmpfmtr->data;
  
      GST_DEBUG_OBJECT (ebin, "Trying formatter %s",
 -        GST_PLUGIN_FEATURE_NAME (formatterfact));
 +        GST_OBJECT_NAME (formatterfact));
  
      if ((formatter =
              _create_element_and_set_preset (formatterfact, preset, NULL)))
@@@ -1549,6 -1582,31 +1591,31 @@@ beach
    return formatter;
  }
  
+ static gint
+ compare_elements (gconstpointer a, gconstpointer b, gpointer udata)
+ {
+   GstCaps *caps = udata;
+   GstElementFactory *fac_a = (GstElementFactory *) a;
+   GstElementFactory *fac_b = (GstElementFactory *) b;
+   /* FIXME not quite sure this is the best algorithm to order the elements
+    * Some caps similarity comparison algorithm would fit better than going
+    * boolean (equals/not equals).
+    */
+   gboolean equals_a = _factory_can_handle_caps (fac_a, caps, GST_PAD_SRC, TRUE);
+   gboolean equals_b = _factory_can_handle_caps (fac_b, caps, GST_PAD_SRC, TRUE);
+   if (equals_a == equals_b) {
+     return gst_plugin_feature_get_rank ((GstPluginFeature *) fac_b) -
+         gst_plugin_feature_get_rank ((GstPluginFeature *) fac_a);
+   } else if (equals_a) {
+     return -1;
+   } else if (equals_b) {
+     return 1;
+   }
+   return 0;
+ }
  static inline GstElement *
  _get_muxer (GstEncodeBin * ebin)
  {
        gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
        TRUE);
  
+   muxers = g_list_sort_with_data (muxers, compare_elements, (gpointer) format);
+   formatters =
+       g_list_sort_with_data (formatters, compare_elements, (gpointer) format);
    muxers = g_list_concat (muxers, formatters);
  
    if (muxers == NULL)
  
      muxerfact = (GstElementFactory *) tmpmux->data;
  
 -    GST_DEBUG ("Trying muxer %s", GST_PLUGIN_FEATURE_NAME (muxerfact));
 +    GST_DEBUG ("Trying muxer %s", GST_OBJECT_NAME (muxerfact));
  
      /* See if the muxer can sink all of our stream profile caps */
      for (tmp = profiles; tmp; tmp = tmp->next) {
        GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
  
-       if (!_factory_can_sink_caps (muxerfact,
-               gst_encoding_profile_get_format (sprof))) {
-         GST_DEBUG ("Skipping muxer because it can't sink caps %" GST_PTR_FORMAT,
-             gst_encoding_profile_get_format (sprof));
+       if (!_factory_can_handle_caps (muxerfact,
+               gst_encoding_profile_get_format (sprof), GST_PAD_SINK, FALSE)) {
+         GST_DEBUG ("Skipping muxer because it can't sink caps %"
+             GST_PTR_FORMAT, gst_encoding_profile_get_format (sprof));
          cansinkstreams = FALSE;
          break;
        }
@@@ -1712,9 -1774,8 +1783,9 @@@ stream_error
  }
  
  static void
 -release_pads (GstPad * pad, GstElement * elt)
 +release_pads (const GValue * item, GstElement * elt)
  {
 +  GstPad *pad = g_value_get_object (item);
    GstPad *peer = NULL;
  
    GST_DEBUG_OBJECT (elt, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
  
    /* Release it from the object */
    gst_element_release_request_pad (elt, pad);
 -
 -  /* And remove the reference added by the iterator */
 -  gst_object_unref (pad);
  }
  
  static void inline
@@@ -1811,9 -1875,7 +1882,9 @@@ stream_group_free (GstEncodeBin * ebin
      GstIteratorResult itret = GST_ITERATOR_OK;
  
      while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
 -      itret = gst_iterator_foreach (it, (GFunc) release_pads, sgroup->combiner);
 +      itret =
 +          gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
 +          sgroup->combiner);
        gst_iterator_resync (it);
      }
      gst_iterator_free (it);
      GstIterator *it = gst_element_iterate_src_pads (sgroup->splitter);
      GstIteratorResult itret = GST_ITERATOR_OK;
      while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
 -      itret = gst_iterator_foreach (it, (GFunc) release_pads, sgroup->splitter);
 +      itret =
 +          gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
 +          sgroup->splitter);
        gst_iterator_resync (it);
      }
      gst_iterator_free (it);
diff --combined gst/playback/Makefile.am
@@@ -6,34 -6,57 +6,36 @@@ glib_gen_basename = gstpla
  built_sources = gstplay-marshal.c
  built_headers = gstplay-marshal.h
  
 -plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin.la libgstdecodebin2.la
 +plugin_LTLIBRARIES = libgstplayback.la
  
 -csp_cflags = -DCOLORSPACE=\"ffmpegcolorspace\"
++csp_cflags = -DCOLORSPACE=\"videoconvert\"
 -libgstplaybin_la_SOURCES = \
 +libgstplayback_la_SOURCES = \
 +      gstdecodebin2.c \
 +      gsturidecodebin.c \
        gstplayback.c \
 -      gstplaybin.c \
        gstplaybin2.c \
        gstplaysink.c \
 -      gstplaybasebin.c \
        gstplay-enum.c \
 -      gststreaminfo.c \
        gststreamselector.c \
        gstsubtitleoverlay.c \
        gstplaysinkvideoconvert.c \
        gstplaysinkaudioconvert.c \
        gststreamsynchronizer.c
  
 -nodist_libgstplaybin_la_SOURCES = $(built_sources)
 -libgstplaybin_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(csp_cflags)
 -libgstplaybin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 -libgstplaybin_la_LIBADD = \
 +nodist_libgstplayback_la_SOURCES = $(built_sources)
- libgstplayback_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
++libgstplayback_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(csp_cflags)
 +libgstplayback_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 +libgstplayback_la_LIBADD = \
        $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
        $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-@GST_MAJORMINOR@.la \
        $(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_MAJORMINOR@.la \
        $(GST_LIBS)
 -libgstplaybin_la_LIBTOOLFLAGS = --tag=disable-static
 -
 -libgstdecodebin_la_SOURCES = gstdecodebin.c
 -nodist_libgstdecodebin_la_SOURCES = $(built_sources)
 -libgstdecodebin_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(csp_cflags)
 -libgstdecodebin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 -libgstdecodebin_la_LIBADD = \
 -      $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
 -      $(GST_LIBS)
 -libgstdecodebin_la_LIBTOOLFLAGS = --tag=disable-static
 -
 -libgstdecodebin2_la_SOURCES = gstdecodebin2.c gsturidecodebin.c gstplay-enum.c
 -nodist_libgstdecodebin2_la_SOURCES = $(built_sources)
 -libgstdecodebin2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(csp_cflags)
 -libgstdecodebin2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 -libgstdecodebin2_la_LIBADD = \
 -      $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
 -      $(GST_LIBS)
 -libgstdecodebin2_la_LIBTOOLFLAGS = --tag=disable-static
 +libgstplayback_la_LIBTOOLFLAGS = --tag=disable-static
  
  noinst_HEADERS = \
        gstplayback.h \
 -      gstplaybasebin.h \
        gstplaysink.h \
 -      gststreaminfo.h \
        gstplay-enum.h \
        gststreamselector.h \
        gstrawcaps.h \
@@@ -52,14 -75,38 +54,14 @@@ include $(top_srcdir)/common/gst-glib-g
  
  Android.mk: Makefile.am $(BUILT_SOURCES)
        androgenizer \
 -      -:PROJECT libgstdecodebin -:SHARED libgstdecodebin \
 -       -:TAGS eng debug \
 -         -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
 -       -:SOURCES $(libgstdecodebin_la_SOURCES) \
 -                 $(nodist_libgstdecodebin_la_SOURCES) \
 -       -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstdecodebin_la_CFLAGS) $(csp_cflags) \
 -       -:LDFLAGS $(libgstdecodebin_la_LDFLAGS) \
 -                 $(libgstdecodebin_la_LIBADD) \
 -                 -ldl \
 -       -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
 -                     LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
 -       \
 -      -:PROJECT libgstdecodebin2 -:SHARED libgstdecodebin2 \
 -       -:TAGS eng debug \
 -         -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
 -       -:SOURCES $(libgstdecodebin2_la_SOURCES) \
 -                 $(nodist_libgstdecodebin2_la_SOURCES) \
 -       -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstdecodebin2_la_CFLAGS) $(csp_cflags) \
 -       -:LDFLAGS $(libgstdecodebin2_la_LDFLAGS) \
 -                 $(libgstdecodebin2_la_LIBADD) \
 -                 -ldl \
 -       -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
 -                     LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
 -       \
 -      -:PROJECT libgstplaybin -:SHARED libgstplaybin \
 +      -:PROJECT libgstplayback -:SHARED libgstplayback \
         -:TAGS eng debug \
           -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
 -       -:SOURCES $(libgstplaybin_la_SOURCES) \
 -                 $(nodist_libgstplaybin_la_SOURCES) \
 -       -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstplaybin_la_CFLAGS) $(csp_cflags) \
 -       -:LDFLAGS $(libgstplaybin_la_LDFLAGS) \
 -                 $(libgstplaybin_la_LIBADD) \
 +       -:SOURCES $(libgstplayback_la_SOURCES) \
 +                 $(nodist_libgstplayback_la_SOURCES) \
-        -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstplayback_la_CFLAGS) \
++       -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstplayback_la_CFLAGS) $(csp_cflags) \
 +       -:LDFLAGS $(libgstplayback_la_LDFLAGS) \
 +                 $(libgstplayback_la_LIBADD) \
                   -ldl \
         -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
                       LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
   */
  
  /**
 - * SECTION:element-decodebin2
 + * SECTION:element-decodebin
   *
   * #GstBin that auto-magically constructs a decoding pipeline using available
   * decoders and demuxers via auto-plugging.
   *
 - * decodebin2 is considered stable now and replaces the old #decodebin element.
 - * #uridecodebin uses decodebin2 internally and is often more convenient to
 + * decodebin is considered stable now and replaces the old #decodebin element.
 + * #uridecodebin uses decodebin internally and is often more convenient to
   * use, as it creates a suitable source element as well.
   */
  
  /* Implementation notes:
   *
 - * The following section describes how decodebin2 works internally.
 + * The following section describes how decodebin works internally.
   *
 - * The first part of decodebin2 is its typefind element, which tries
 + * The first part of decodebin is its typefind element, which tries
   * to determine the media type of the input stream. If the type is found
   * autoplugging starts.
   *
 - * decodebin2 internally organizes the elements it autoplugged into GstDecodeChains
 + * decodebin internally organizes the elements it autoplugged into GstDecodeChains
   * and GstDecodeGroups. A decode chain is a single chain of decoding, this
 - * means that if decodebin2 every autoplugs an element with two+ srcpads
 + * means that if decodebin every autoplugs an element with two+ srcpads
   * (e.g. a demuxer) this will end the chain and everything following this
   * demuxer will be put into decode groups below the chain. Otherwise,
   * if an element has a single srcpad that outputs raw data the decode chain
   * chains are complete.
   *
   * If this happens at some point, all endpads of all active groups are exposed.
 - * For this decodebin2 adds the endpads, signals no-more-pads and then unblocks
 + * For this decodebin adds the endpads, signals no-more-pads and then unblocks
   * them. Now playback starts.
   *
 - * If one of the chains that end on a endpad receives EOS decodebin2 checks
 + * If one of the chains that end on a endpad receives EOS decodebin checks
   * if all chains and groups are drained. In that case everything goes into EOS.
   * If there is a chain where the active group is drained but there exist next
   * groups, the active group is hidden (endpads are removed) and the next group
@@@ -116,6 -116,7 +116,6 @@@ typedef struct _GstDecodeGroup GstDecod
  typedef struct _GstDecodePad GstDecodePad;
  typedef GstGhostPadClass GstDecodePadClass;
  typedef struct _GstDecodeBin GstDecodeBin;
 -typedef struct _GstDecodeBin GstDecodeBin2;
  typedef struct _GstDecodeBinClass GstDecodeBinClass;
  
  #define GST_TYPE_DECODE_BIN             (gst_decode_bin_get_type())
  #define GST_IS_DECODE_BIN_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DECODE_BIN))
  
  /**
 - *  GstDecodeBin2:
 + *  GstDecodeBin:
   *
 - *  The opaque #DecodeBin2 data structure
 + *  The opaque #GstDecodeBin data structure
   */
  struct _GstDecodeBin
  {
@@@ -177,6 -178,10 +177,6 @@@ struct _GstDecodeBinClas
  {
    GstBinClass parent_class;
  
 -  /* signal we fire when a new pad has been decoded into raw audio/video */
 -  void (*new_decoded_pad) (GstElement * element, GstPad * pad, gboolean last);
 -  /* signal we fire when a pad has been removed */
 -  void (*removed_decoded_pad) (GstElement * element, GstPad * pad);
    /* signal fired when we found a pad that we cannot decode */
    void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps);
  
  /* signals */
  enum
  {
 -  SIGNAL_NEW_DECODED_PAD,
 -  SIGNAL_REMOVED_DECODED_PAD,
    SIGNAL_UNKNOWN_TYPE,
    SIGNAL_AUTOPLUG_CONTINUE,
    SIGNAL_AUTOPLUG_FACTORIES,
@@@ -458,8 -465,6 +458,8 @@@ struct _GstDecodePa
    gboolean blocked;             /* the *target* pad is blocked */
    gboolean exposed;             /* the pad is exposed */
    gboolean drained;             /* an EOS has been seen on the pad */
 +
 +  gulong block_id;
  };
  
  GType gst_decode_pad_get_type (void);
@@@ -475,8 -480,7 +475,8 @@@ static void gst_decode_pad_unblock (Gst
  static void gst_decode_pad_set_blocked (GstDecodePad * dpad, gboolean blocked);
  
  static void gst_pending_pad_free (GstPendingPad * ppad);
 -static gboolean pad_event_cb (GstPad * pad, GstEvent * event, gpointer data);
 +static GstProbeReturn pad_event_cb (GstPad * pad, GstProbeType type,
 +    gpointer type_data, gpointer data);
  
  /********************************
   * Standard GObject boilerplate *
@@@ -507,7 -511,7 +507,7 @@@ gst_decode_bin_get_type (void
      };
  
      gst_decode_bin_type =
 -        g_type_register_static (GST_TYPE_BIN, "GstDecodeBin2",
 +        g_type_register_static (GST_TYPE_BIN, "GstDecodeBin",
          &gst_decode_bin_info, 0);
    }
  
@@@ -588,7 -592,42 +588,7 @@@ gst_decode_bin_class_init (GstDecodeBin
    gobject_klass->get_property = gst_decode_bin_get_property;
  
    /**
 -   * GstDecodeBin2::new-decoded-pad:
 -   * @bin: The decodebin.
 -   * @pad: The newly created pad.
 -   * @islast: #TRUE if this is the last pad to be added. Deprecated.
 -   *
 -   * This signal gets emitted as soon as a new pad of the same type as one of
 -   * the valid 'raw' types is added.
 -   *
 -   * Deprecated: Use GstElement::pad-added instead of this signal.
 -   *
 -   */
 -  gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD] =
 -      g_signal_new ("new-decoded-pad", G_TYPE_FROM_CLASS (klass),
 -      G_SIGNAL_RUN_LAST,
 -      G_STRUCT_OFFSET (GstDecodeBinClass, new_decoded_pad), NULL, NULL,
 -      gst_play_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, GST_TYPE_PAD,
 -      G_TYPE_BOOLEAN);
 -
 -  /**
 -   * GstDecodeBin2::removed-decoded-pad:
 -   * @bin: The decodebin.
 -   * @pad: The pad that was removed.
 -   *
 -   * This signal is emitted when a 'final' caps pad has been removed.
 -   *
 -   * Deprecated: Use GstElement::pad-removed instead of this signal.
 -   *
 -   */
 -  gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD] =
 -      g_signal_new ("removed-decoded-pad", G_TYPE_FROM_CLASS (klass),
 -      G_SIGNAL_RUN_LAST,
 -      G_STRUCT_OFFSET (GstDecodeBinClass, removed_decoded_pad), NULL, NULL,
 -      gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
 -
 -  /**
 -   * GstDecodeBin2::unknown-type:
 +   * GstDecodeBin::unknown-type:
     * @bin: The decodebin.
     * @pad: The new pad containing caps that cannot be resolved to a 'final'
     *       stream type.
        GST_TYPE_PAD, GST_TYPE_CAPS);
  
    /**
 -   * GstDecodeBin2::autoplug-continue:
 +   * GstDecodeBin::autoplug-continue:
     * @bin: The decodebin.
     * @pad: The #GstPad.
     * @caps: The #GstCaps found.
     *
 -   * This signal is emitted whenever decodebin2 finds a new stream. It is
 +   * This signal is emitted whenever decodebin finds a new stream. It is
     * emitted before looking for any elements that can handle that stream.
     *
     * <note>
     *   connected in.
     * </note>
     *
 -   * Returns: #TRUE if you wish decodebin2 to look for elements that can
 +   * Returns: #TRUE if you wish decodebin to look for elements that can
     * handle the given @caps. If #FALSE, those caps will be considered as
 -   * final and the pad will be exposed as such (see 'new-decoded-pad'
 -   * signal).
 +   * final and the pad will be exposed as such (see 'pad-added' signal of
 +   * #GstElement).
     */
    gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE] =
        g_signal_new ("autoplug-continue", G_TYPE_FROM_CLASS (klass),
        G_TYPE_BOOLEAN, 2, GST_TYPE_PAD, GST_TYPE_CAPS);
  
    /**
 -   * GstDecodeBin2::autoplug-factories:
 +   * GstDecodeBin::autoplug-factories:
     * @bin: The decodebin.
     * @pad: The #GstPad.
     * @caps: The #GstCaps found.
     *
     * This function is emited when an array of possible factories for @caps on
 -   * @pad is needed. Decodebin2 will by default return an array with all
 +   * @pad is needed. Decodebin will by default return an array with all
     * compatible factories, sorted by rank.
     *
     * If this function returns NULL, @pad will be exposed as a final caps.
        GST_TYPE_PAD, GST_TYPE_CAPS);
  
    /**
 -   * GstDecodeBin2::autoplug-sort:
 +   * GstDecodeBin::autoplug-sort:
     * @bin: The decodebin.
     * @pad: The #GstPad.
     * @caps: The #GstCaps.
     * @factories: A #GValueArray of possible #GstElementFactory to use.
     *
 -   * Once decodebin2 has found the possible #GstElementFactory objects to try
 +   * Once decodebin has found the possible #GstElementFactory objects to try
     * for @caps on @pad, this signal is emited. The purpose of the signal is for
     * the application to perform additional sorting or filtering on the element
     * factory array.
        GST_TYPE_PAD, GST_TYPE_CAPS, G_TYPE_VALUE_ARRAY);
  
    /**
 -   * GstDecodeBin2::autoplug-select:
 +   * GstDecodeBin::autoplug-select:
     * @bin: The decodebin.
     * @pad: The #GstPad.
     * @caps: The #GstCaps.
     * @factory: A #GstElementFactory to use.
     *
 -   * This signal is emitted once decodebin2 has found all the possible
 +   * This signal is emitted once decodebin has found all the possible
     * #GstElementFactory that can be used to handle the given @caps. For each of
     * those factories, this signal is emited.
     *
     * The signal handler should return a #GST_TYPE_AUTOPLUG_SELECT_RESULT enum
 -   * value indicating what decodebin2 should do next.
 +   * value indicating what decodebin should do next.
     *
     * A value of #GST_AUTOPLUG_SELECT_TRY will try to autoplug an element from
     * @factory.
        GST_TYPE_ELEMENT_FACTORY);
  
    /**
 -   * GstDecodeBin2::drained
 +   * GstDecodeBin::drained
     * @bin: The decodebin
     *
 -   * This signal is emitted once decodebin2 has finished decoding all the data.
 +   * This signal is emitted once decodebin has finished decoding all the data.
     *
     * Since: 0.10.16
     */
            GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
    /**
 -   * GstDecodeBin2::use-buffering
 +   * GstDecodeBin::use-buffering
     *
 -   * Activate buffering in decodebin2. This will instruct the multiqueues behind
 +   * Activate buffering in decodebin. This will instruct the multiqueues behind
     * decoders to emit BUFFERING messages.
  
     * Since: 0.10.26
            DEFAULT_USE_BUFFERING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
    /**
 -   * GstDecodebin2:low-percent
 +   * GstDecodeBin:low-percent
     *
     * Low threshold percent for buffering to start.
     *
            "Low threshold for buffering to start", 0, 100,
            DEFAULT_LOW_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
    /**
 -   * GstDecodebin2:high-percent
 +   * GstDecodeBin:high-percent
     *
     * High threshold percent for buffering to finish.
     *
            DEFAULT_HIGH_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
    /**
 -   * GstDecodebin2:max-size-bytes
 +   * GstDecodeBin:max-size-bytes
     *
     * Max amount amount of bytes in the queue (0=automatic).
     *
            0, G_MAXUINT, DEFAULT_MAX_SIZE_BYTES,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
    /**
 -   * GstDecodebin2:max-size-buffers
 +   * GstDecodeBin:max-size-buffers
     *
     * Max amount amount of buffers in the queue (0=automatic).
     *
            0, G_MAXUINT, DEFAULT_MAX_SIZE_BUFFERS,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
    /**
 -   * GstDecodebin2:max-size-time
 +   * GstDecodeBin:max-size-time
     *
     * Max amount amount of time in the queue (in ns, 0=automatic).
     *
            DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
    /**
 -   * GstDecodeBin2::post-stream-topology
 +   * GstDecodeBin::post-stream-topology
     *
     * Post stream-topology messages on the bus every time the topology changes.
     *
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
    /**
 -   * GstDecodeBin2::expose-all-streams
 +   * GstDecodeBin::expose-all-streams
     *
     * Expose streams of unknown type.
     *
@@@ -1438,7 -1477,7 +1438,7 @@@ analyze_new_pad (GstDecodeBin * dbin, G
  
      for (i = 0; i < factories->n_values && !dontuse; i++) {
        GstElementFactory *factory =
-           g_value_get_object (g_value_array_get_nth (factories, 0));
+           g_value_get_object (g_value_array_get_nth (factories, i));
        GstCaps *tcaps;
  
        /* We are only interested in skipping decoders */
@@@ -1575,11 -1614,11 +1575,11 @@@ setup_caps_delay
      ppad->pad = gst_object_ref (pad);
      ppad->chain = chain;
      ppad->event_probe_id =
 -        gst_pad_add_event_probe (pad, (GCallback) pad_event_cb, ppad);
 +        gst_pad_add_probe (pad, GST_PROBE_TYPE_EVENT, pad_event_cb, ppad, NULL);
      chain->pending_pads = g_list_prepend (chain->pending_pads, ppad);
-     CHAIN_MUTEX_UNLOCK (chain);
      g_signal_connect (G_OBJECT (pad), "notify::caps",
          G_CALLBACK (caps_notify_cb), chain);
+     CHAIN_MUTEX_UNLOCK (chain);
      return;
    }
  }
@@@ -1802,7 -1841,7 +1802,7 @@@ connect_pad (GstDecodeBin * dbin, GstEl
            }
  
            g_signal_handlers_disconnect_by_func (pp->pad, caps_notify_cb, chain);
 -          gst_pad_remove_event_probe (pp->pad, pp->event_probe_id);
 +          gst_pad_remove_probe (pp->pad, pp->event_probe_id);
            gst_object_unref (pp->pad);
            g_slice_free (GstPendingPad, pp);
  
@@@ -1849,13 -1888,16 +1849,13 @@@ get_pad_caps (GstPad * pad
  
    /* first check the pad caps, if this is set, we are positively sure it is
     * fixed and exactly what the element will produce. */
 -  GST_OBJECT_LOCK (pad);
 -  if ((caps = GST_PAD_CAPS (pad)))
 -    gst_caps_ref (caps);
 -  GST_OBJECT_UNLOCK (pad);
 +  caps = gst_pad_get_current_caps (pad);
  
    /* then use the getcaps function if we don't have caps. These caps might not
     * be fixed in some cases, in which case analyze_new_pad will set up a
     * notify::caps signal to continue autoplugging. */
    if (caps == NULL)
 -    caps = gst_pad_get_caps_reffed (pad);
 +    caps = gst_pad_get_caps (pad, NULL);
  
    return caps;
  }
@@@ -2032,8 -2074,10 +2032,8 @@@ check_upstream_seekable (GstDecodeBin 
  
    /* try harder to query upstream size if we didn't get it the first time */
    if (dbin->upstream_seekable && stop == -1) {
 -    GstFormat fmt = GST_FORMAT_BYTES;
 -
      GST_DEBUG_OBJECT (dbin, "doing duration query to fix up unset stop");
 -    gst_pad_query_peer_duration (pad, &fmt, &stop);
 +    gst_pad_query_peer_duration (pad, GST_FORMAT_BYTES, &stop);
    }
  
    /* if upstream doesn't know the size, it's likely that it's not seekable in
@@@ -2060,7 -2104,7 +2060,7 @@@ type_found (GstElement * typefind, guin
    if (gst_structure_has_name (gst_caps_get_structure (caps, 0), "text/plain")) {
      GST_ELEMENT_ERROR (decode_bin, STREAM, WRONG_TYPE,
          (_("This appears to be a text file")),
 -        ("decodebin2 cannot decode plain text files"));
 +        ("decodebin cannot decode plain text files"));
      goto exit;
    }
  
@@@ -2094,11 -2138,9 +2094,11 @@@ exit
    return;
  }
  
 -static gboolean
 -pad_event_cb (GstPad * pad, GstEvent * event, gpointer data)
 +static GstProbeReturn
 +pad_event_cb (GstPad * pad, GstProbeType type, gpointer type_data,
 +    gpointer data)
  {
 +  GstEvent *event = type_data;
    GstPendingPad *ppad = (GstPendingPad *) data;
    GstDecodeChain *chain = ppad->chain;
    GstDecodeBin *dbin = chain->dbin;
      default:
        break;
    }
 -  return TRUE;
 +  return GST_PROBE_OK;
  }
  
  static void
@@@ -2456,6 -2498,8 +2456,6 @@@ gst_decode_chain_free_internal (GstDeco
      if (chain->endpad->exposed) {
        gst_element_remove_pad (GST_ELEMENT_CAST (chain->dbin),
            GST_PAD_CAST (chain->endpad));
 -      g_signal_emit (G_OBJECT (chain->dbin),
 -          gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD], 0, chain->endpad);
      }
  
      gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->endpad), NULL);
  /* gst_decode_chain_free:
   *
   * Completely frees and removes the chain and all
 - * child groups from decodebin2.
 + * child groups from decodebin.
   *
   * MT-safe, don't hold the chain lock or any child chain's lock
   * when calling this!
@@@ -2628,7 -2672,7 +2628,7 @@@ gst_decode_group_free (GstDecodeGroup 
  /* gst_decode_group_hide:
   *
   * Hide the decode group only, this means that
 - * all child endpads are removed from decodebin2
 + * all child endpads are removed from decodebin
   * and all signals are unconnected.
   *
   * No element is set to NULL state and completely
@@@ -2746,7 -2790,6 +2746,7 @@@ gst_decode_group_control_demuxer_pad (G
    GstDecodeBin *dbin;
    GstPad *srcpad, *sinkpad;
    GstIterator *it = NULL;
 +  GValue item = { 0, };
  
    dbin = group->dbin;
  
  
    it = gst_pad_iterate_internal_links (sinkpad);
  
 -  if (!it || (gst_iterator_next (it, (gpointer) & srcpad)) != GST_ITERATOR_OK
 -      || srcpad == NULL) {
 +  if (!it || (gst_iterator_next (it, &item)) != GST_ITERATOR_OK
 +      || ((srcpad = g_value_dup_object (&item)) == NULL)) {
      GST_ERROR_OBJECT (dbin,
          "Couldn't get srcpad from multiqueue for sinkpad %" GST_PTR_FORMAT,
          sinkpad);
      goto error;
    }
 -
    CHAIN_MUTEX_LOCK (group->parent);
    group->reqpads = g_list_prepend (group->reqpads, gst_object_ref (sinkpad));
    CHAIN_MUTEX_UNLOCK (group->parent);
  
  beach:
 +  g_value_unset (&item);
    if (it)
      gst_iterator_free (it);
    gst_object_unref (sinkpad);
@@@ -3050,7 -3093,7 +3050,7 @@@ sort_end_pads (GstDecodePad * da, GstDe
    namea = gst_structure_get_name (sa);
    nameb = gst_structure_get_name (sb);
  
 -  if (g_strrstr (namea, "video/x-raw-"))
 +  if (g_strrstr (namea, "video/x-raw"))
      va = 0;
    else if (g_strrstr (namea, "video/"))
      va = 1;
    else
      va = 4;
  
 -  if (g_strrstr (nameb, "video/x-raw-"))
 +  if (g_strrstr (nameb, "video/x-raw"))
      vb = 0;
    else if (g_strrstr (nameb, "video/"))
      vb = 1;
@@@ -3086,18 -3129,16 +3086,18 @@@ _gst_element_get_linked_caps (GstElemen
    GstPad *pad, *peer;
    gboolean done = FALSE;
    GstCaps *caps = NULL;
 +  GValue item = { 0, };
  
    it = gst_element_iterate_src_pads (src);
    while (!done) {
 -    switch (gst_iterator_next (it, (gpointer) & pad)) {
 +    switch (gst_iterator_next (it, &item)) {
        case GST_ITERATOR_OK:
 +        pad = g_value_get_object (&item);
          peer = gst_pad_get_peer (pad);
          if (peer) {
            parent = gst_pad_get_parent_element (peer);
            if (parent == sink) {
 -            caps = gst_pad_get_negotiated_caps (pad);
 +            caps = gst_pad_get_current_caps (pad);
              done = TRUE;
            }
  
              gst_object_unref (parent);
            gst_object_unref (peer);
          }
 -        gst_object_unref (pad);
 +        g_value_reset (&item);
          break;
        case GST_ITERATOR_RESYNC:
          gst_iterator_resync (it);
          break;
      }
    }
 -
 +  g_value_unset (&item);
    gst_iterator_free (it);
  
    return caps;
@@@ -3193,7 -3234,7 +3193,7 @@@ gst_decode_chain_get_topology (GstDecod
    }
  
    /* Caps that resulted in this chain */
 -  caps = gst_pad_get_negotiated_caps (chain->pad);
 +  caps = gst_pad_get_current_caps (chain->pad);
    if (!caps) {
      caps = get_pad_caps (chain->pad);
      if (G_UNLIKELY (!gst_caps_is_fixed (caps))) {
@@@ -3309,13 -3350,17 +3309,13 @@@ gst_decode_bin_expose (GstDecodeBin * d
      if (!dpad->exposed
          && !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");
 +      g_warning ("error adding pad to decodebin");
        continue;
      }
      dpad->exposed = TRUE;
  
      /* 3. emit signal */
 -    GST_DEBUG_OBJECT (dbin, "emitting new-decoded-pad");
 -    g_signal_emit (G_OBJECT (dbin),
 -        gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, dpad,
 -        (tmp->next == NULL));
 -    GST_DEBUG_OBJECT (dbin, "emitted new-decoded-pad");
 +    GST_INFO_OBJECT (dpad, "added new decoded pad");
    }
  
    /* 4. Signal no-more-pads. This allows the application to hook stuff to the
@@@ -3420,40 -3465,36 +3420,40 @@@ gst_decode_pad_init (GstDecodePad * pad
    pad->blocked = FALSE;
    pad->exposed = FALSE;
    pad->drained = FALSE;
 -  gst_object_ref (pad);
 -  gst_object_sink (pad);
 +  gst_object_ref_sink (pad);
  }
  
 -static void
 -source_pad_blocked_cb (GstPad * pad, gboolean blocked, GstDecodePad * dpad)
 +static GstProbeReturn
 +source_pad_blocked_cb (GstPad * pad, GstProbeType type, gpointer type_data,
 +    gpointer user_data)
  {
 +  GstDecodePad *dpad = user_data;
    GstDecodeChain *chain;
    GstDecodeBin *dbin;
  
    chain = dpad->chain;
    dbin = chain->dbin;
  
 -  GST_LOG_OBJECT (dpad, "blocked:%d, dpad->chain:%p", blocked, chain);
 +  GST_LOG_OBJECT (dpad, "blocked: dpad->chain:%p", chain);
  
 -  dpad->blocked = blocked;
 +  dpad->blocked = TRUE;
  
 -  if (dpad->blocked) {
 -    EXPOSE_LOCK (dbin);
 -    if (gst_decode_chain_is_complete (dbin->decode_chain)) {
 -      if (!gst_decode_bin_expose (dbin))
 -        GST_WARNING_OBJECT (dbin, "Couldn't expose group");
 -    }
 -    EXPOSE_UNLOCK (dbin);
 +  EXPOSE_LOCK (dbin);
 +  if (gst_decode_chain_is_complete (dbin->decode_chain)) {
 +    if (!gst_decode_bin_expose (dbin))
 +      GST_WARNING_OBJECT (dbin, "Couldn't expose group");
    }
 +  EXPOSE_UNLOCK (dbin);
 +
 +  return GST_PROBE_OK;
  }
  
 -static gboolean
 -source_pad_event_probe (GstPad * pad, GstEvent * event, GstDecodePad * dpad)
 +static GstProbeReturn
 +source_pad_event_probe (GstPad * pad, GstProbeType type, gpointer type_data,
 +    gpointer user_data)
  {
 +  GstEvent *event = type_data;
 +  GstDecodePad *dpad = user_data;
    gboolean res = TRUE;
  
    GST_LOG_OBJECT (pad, "%s dpad:%p", GST_EVENT_TYPE_NAME (event), dpad);
       *   first, which unlinks the peer and so drops the EOS. */
      res = gst_decode_pad_handle_eos (dpad);
    }
 -
 -  return res;
 +  if (res)
 +    return GST_PROBE_OK;
 +  else
 +    return GST_PROBE_DROP;
  }
  
  static void
@@@ -3492,20 -3531,10 +3492,20 @@@ gst_decode_pad_set_blocked (GstDecodePa
  
    /* do not block if shutting down.
     * we do not consider/expect it blocked further below, but use other trick */
 -  if (!blocked || !dbin->shutdown)
 -    gst_pad_set_blocked_async_full (opad, blocked,
 -        (GstPadBlockCallback) source_pad_blocked_cb, gst_object_ref (dpad),
 -        (GDestroyNotify) gst_object_unref);
 +  if (!blocked || !dbin->shutdown) {
 +    if (blocked) {
 +      if (dpad->block_id == 0)
 +        dpad->block_id = gst_pad_add_probe (opad, GST_PROBE_TYPE_BLOCK,
 +            source_pad_blocked_cb, gst_object_ref (dpad),
 +            (GDestroyNotify) gst_object_unref);
 +    } else {
 +      if (dpad->block_id != 0) {
 +        gst_pad_remove_probe (opad, dpad->block_id);
 +        dpad->block_id = 0;
 +      }
 +      dpad->blocked = FALSE;
 +    }
 +  }
  
    if (blocked) {
      if (dbin->shutdown) {
@@@ -3534,8 -3563,8 +3534,8 @@@ out
  static void
  gst_decode_pad_add_drained_check (GstDecodePad * dpad)
  {
 -  gst_pad_add_event_probe (GST_PAD_CAST (dpad),
 -      G_CALLBACK (source_pad_event_probe), dpad);
 +  gst_pad_add_probe (GST_PAD_CAST (dpad), GST_PROBE_TYPE_EVENT,
 +      source_pad_event_probe, dpad, NULL);
  }
  
  static void
@@@ -3586,7 -3615,7 +3586,7 @@@ gst_pending_pad_free (GstPendingPad * p
    g_assert (ppad->pad);
  
    if (ppad->event_probe_id != 0)
 -    gst_pad_remove_event_probe (ppad->pad, ppad->event_probe_id);
 +    gst_pad_remove_probe (ppad->pad, ppad->event_probe_id);
    gst_object_unref (ppad->pad);
    g_slice_free (GstPendingPad, ppad);
  }
@@@ -3602,7 -3631,7 +3602,7 @@@ do_async_start (GstDecodeBin * dbin
  
    dbin->async_pending = TRUE;
  
 -  message = gst_message_new_async_start (GST_OBJECT_CAST (dbin), FALSE);
 +  message = gst_message_new_async_start (GST_OBJECT_CAST (dbin));
    parent_class->handle_message (GST_BIN_CAST (dbin), message);
  }
  
@@@ -3612,7 -3641,7 +3612,7 @@@ do_async_done (GstDecodeBin * dbin
    GstMessage *message;
  
    if (dbin->async_pending) {
 -    message = gst_message_new_async_done (GST_OBJECT_CAST (dbin));
 +    message = gst_message_new_async_done (GST_OBJECT_CAST (dbin), FALSE);
      parent_class->handle_message (GST_BIN_CAST (dbin), message);
  
      dbin->async_pending = FALSE;
@@@ -3634,13 -3663,13 +3634,13 @@@ find_sink_pad (GstElement * element
  {
    GstIterator *it;
    GstPad *pad = NULL;
 -  gpointer point;
 +  GValue item = { 0, };
  
    it = gst_element_iterate_sink_pads (element);
  
 -  if ((gst_iterator_next (it, &point)) == GST_ITERATOR_OK)
 -    pad = (GstPad *) point;
 -
 +  if ((gst_iterator_next (it, &item)) == GST_ITERATOR_OK)
 +    pad = g_value_dup_object (&item);
 +  g_value_unset (&item);
    gst_iterator_free (it);
  
    return pad;
@@@ -3663,11 -3692,9 +3663,11 @@@ unblock_pads (GstDecodeBin * dbin
        continue;
  
      GST_DEBUG_OBJECT (dpad, "unblocking");
 -    gst_pad_set_blocked_async_full (opad, FALSE,
 -        (GstPadBlockCallback) source_pad_blocked_cb, gst_object_ref (dpad),
 -        (GDestroyNotify) gst_object_unref);
 +    if (dpad->block_id != 0) {
 +      gst_pad_remove_probe (opad, dpad->block_id);
 +      dpad->block_id = 0;
 +    }
 +    dpad->blocked = FALSE;
      /* make flushing, prevent NOT_LINKED */
      GST_PAD_SET_FLUSHING (GST_PAD_CAST (dpad));
      gst_object_unref (dpad);
@@@ -3760,7 -3787,15 +3760,7 @@@ activate_failed
  gboolean
  gst_decode_bin_plugin_init (GstPlugin * plugin)
  {
 -  GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin2", 0,
 -      "decoder bin");
 -
 -#ifdef ENABLE_NLS
 -  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
 -      LOCALEDIR);
 -  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
 -  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 -#endif /* ENABLE_NLS */
 +  GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin", 0, "decoder bin");
  
    /* Register some quarks here for the stream topology message */
    topology_structure_name = g_quark_from_static_string ("stream-topology");
    topology_next = g_quark_from_static_string ("next");
    topology_pad = g_quark_from_static_string ("pad");
  
 -  return gst_element_register (plugin, "decodebin2", GST_RANK_NONE,
 +  return gst_element_register (plugin, "decodebin", GST_RANK_NONE,
        GST_TYPE_DECODE_BIN);
  }
@@@ -166,7 -166,6 +166,7 @@@ struct _GstPlaySin
    gboolean audio_pad_blocked;
    GstPad *audio_srcpad_stream_synchronizer;
    GstPad *audio_sinkpad_stream_synchronizer;
 +  gulong audio_block_id;
    /* audio tee */
    GstElement *audio_tee;
    GstPad *audio_tee_sink;
    gboolean video_pad_blocked;
    GstPad *video_srcpad_stream_synchronizer;
    GstPad *video_sinkpad_stream_synchronizer;
 +  gulong video_block_id;
    /* text */
    GstPad *text_pad;
    gboolean text_pad_blocked;
    GstPad *text_srcpad_stream_synchronizer;
    GstPad *text_sinkpad_stream_synchronizer;
 +  gulong text_block_id;
  
    guint32 pending_blocked_pads;
  
@@@ -271,7 -268,7 +271,7 @@@ static void gst_play_sink_get_property 
      GValue * value, GParamSpec * spec);
  
  static GstPad *gst_play_sink_request_new_pad (GstElement * element,
 -    GstPadTemplate * templ, const gchar * name);
 +    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
  static void gst_play_sink_release_request_pad (GstElement * element,
      GstPad * pad);
  static gboolean gst_play_sink_send_event (GstElement * element,
@@@ -391,7 -388,7 +391,7 @@@ gst_play_sink_class_init (GstPlaySinkCl
     * Since: 0.10.30
     */
    g_object_class_install_property (gobject_klass, PROP_FRAME,
 -      gst_param_spec_mini_object ("frame", "Frame",
 +      g_param_spec_boxed ("frame", "Frame",
            "The last frame (NULL = no video available)",
            GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
    /**
@@@ -679,9 -676,21 +679,9 @@@ gst_play_sink_get_sink (GstPlaySink * p
    return result;
  }
  
 -static void
 -gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked,
 -    gpointer user_data)
 -{
 -  GstPlaySink *playsink;
 -
 -  playsink = GST_PLAY_SINK (user_data);
 -  /* nothing to do here, we need a dummy callback here to make the async call
 -   * non-blocking. */
 -  GST_DEBUG_OBJECT (playsink, "vis pad unblocked");
 -}
 -
 -static void
 -gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
 -    gpointer user_data)
 +static GstProbeReturn
 +gst_play_sink_vis_blocked (GstPad * tee_pad, GstProbeType type,
 +    gpointer type_data, gpointer user_data)
  {
    GstPlaySink *playsink;
    GstPlayVisChain *chain;
        chain->vissrcpad);
  
  done:
 -  /* Unblock the pad */
 -  gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
 -      playsink);
    GST_PLAY_SINK_UNLOCK (playsink);
 +
 +  /* remove the probe and unblock the pad */
 +  return GST_PROBE_REMOVE;
  }
  
  void
@@@ -758,8 -767,8 +758,8 @@@ gst_play_sink_set_vis_plugin (GstPlaySi
     * function returns FALSE but the previous pad block will do the right thing
     * anyway. */
    GST_DEBUG_OBJECT (playsink, "blocking vis pad");
 -  gst_pad_set_blocked_async (chain->blockpad, TRUE, gst_play_sink_vis_blocked,
 -      playsink);
 +  gst_pad_add_probe (chain->blockpad, GST_PROBE_TYPE_BLOCK,
 +      gst_play_sink_vis_blocked, playsink, NULL);
  done:
    GST_PLAY_SINK_UNLOCK (playsink);
  
@@@ -968,14 -977,15 +968,14 @@@ typedef struc
  } FindPropertyHelper;
  
  static gint
 -find_property (GstElement * element, FindPropertyHelper * helper)
 +find_property (const GValue * item, FindPropertyHelper * helper)
  {
 +  GstElement *element = g_value_get_object (item);
    if (helper->need_sink && !element_is_sink (element)) {
 -    gst_object_unref (element);
      return 1;
    }
  
    if (!element_has_property (element, helper->prop_name, helper->prop_type)) {
 -    gst_object_unref (element);
      return 1;
    }
  
@@@ -998,19 -1008,15 +998,19 @@@ gst_play_sink_find_property_sinks (GstP
    if (element_has_property (obj, name, expected_type)) {
      result = obj;
    } else if (GST_IS_BIN (obj)) {
 +    gboolean found;
 +    GValue item = { 0, };
      FindPropertyHelper helper = { name, expected_type, TRUE };
  
      it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
 -    result = gst_iterator_find_custom (it,
 -        (GCompareFunc) find_property, &helper);
 +    found = gst_iterator_find_custom (it,
 +        (GCompareFunc) find_property, &item, &helper);
      gst_iterator_free (it);
 -    /* we don't need the extra ref */
 -    if (result)
 -      gst_object_unref (result);
 +    if (found) {
 +      result = g_value_get_object (&item);
 +      /* we don't need the extra ref */
 +      g_value_unset (&item);
 +    }
    }
    return result;
  }
@@@ -1024,17 -1030,12 +1024,17 @@@ gst_play_sink_find_property (GstPlaySin
    GstIterator *it;
  
    if (GST_IS_BIN (obj)) {
 +    gboolean found;
 +    GValue item = { 0, };
      FindPropertyHelper helper = { name, expected_type, FALSE };
  
      it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
 -    result = gst_iterator_find_custom (it,
 -        (GCompareFunc) find_property, &helper);
 +    found = gst_iterator_find_custom (it,
 +        (GCompareFunc) find_property, &item, &helper);
      gst_iterator_free (it);
 +    if (found)
 +      result = g_value_dup_object (&item);
 +    g_value_unset (&item);
    } else {
      if (element_has_property (obj, name, expected_type)) {
        result = obj;
@@@ -1057,7 -1058,7 +1057,7 @@@ do_async_start (GstPlaySink * playsink
    playsink->async_pending = TRUE;
  
    GST_INFO_OBJECT (playsink, "Sending async_start message");
 -  message = gst_message_new_async_start (GST_OBJECT_CAST (playsink), FALSE);
 +  message = gst_message_new_async_start (GST_OBJECT_CAST (playsink));
    GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (GST_BIN_CAST
        (playsink), message);
  }
@@@ -1069,7 -1070,7 +1069,7 @@@ do_async_done (GstPlaySink * playsink
  
    if (playsink->async_pending) {
      GST_INFO_OBJECT (playsink, "Sending async_done message");
 -    message = gst_message_new_async_done (GST_OBJECT_CAST (playsink));
 +    message = gst_message_new_async_done (GST_OBJECT_CAST (playsink), FALSE);
      GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (GST_BIN_CAST
          (playsink), message);
  
@@@ -1132,13 -1133,13 +1132,13 @@@ gen_video_deinterlace_chain (GstPlaySin
    bin = GST_BIN_CAST (chain->chain.bin);
    gst_object_ref_sink (bin);
  
-   GST_DEBUG_OBJECT (playsink, "creating videoconvert");
-   chain->conv = gst_element_factory_make ("videoconvert", "vdconv");
+   GST_DEBUG_OBJECT (playsink, "creating " COLORSPACE);
+   chain->conv = gst_element_factory_make (COLORSPACE, "vdconv");
    if (chain->conv == NULL) {
-     post_missing_element_message (playsink, "videoconvert");
+     post_missing_element_message (playsink, COLORSPACE);
      GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
          (_("Missing element '%s' - check your GStreamer installation."),
-             "videoconvert"), ("video rendering might fail"));
+             COLORSPACE), ("video rendering might fail"));
    } else {
      gst_bin_add (bin, chain->conv);
      head = chain->conv;
@@@ -2212,7 -2213,6 +2212,7 @@@ gst_play_sink_reconfigure (GstPlaySink 
        goto no_chain;
  
      if (!playsink->video_sinkpad_stream_synchronizer) {
 +      GValue item = { 0, };
        GstIterator *it;
  
        playsink->video_sinkpad_stream_synchronizer =
        it = gst_pad_iterate_internal_links
            (playsink->video_sinkpad_stream_synchronizer);
        g_assert (it);
 -      gst_iterator_next (it,
 -          (gpointer *) & playsink->video_srcpad_stream_synchronizer);
 +      gst_iterator_next (it, &item);
 +      playsink->video_srcpad_stream_synchronizer = g_value_dup_object (&item);
 +      g_value_unset (&item);
        g_assert (playsink->video_srcpad_stream_synchronizer);
        gst_iterator_free (it);
      }
  
        add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
        activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
-       gst_object_replace ((GstObject **) & playsink->videochain->ts_offset,
-           NULL);
+       if (playsink->videochain->ts_offset)
+         gst_object_unref (playsink->videochain->ts_offset);
+       playsink->videochain->ts_offset = NULL;
      }
  
      if (playsink->videodeinterlacechain) {
          disconnect_chain (playsink->audiochain, playsink);
          playsink->audiochain->volume = NULL;
          playsink->audiochain->mute = NULL;
-         gst_object_replace ((GstObject **) & playsink->audiochain->ts_offset,
-             NULL);
+         if (playsink->audiochain->ts_offset)
+           gst_object_unref (playsink->audiochain->ts_offset);
+         playsink->audiochain->ts_offset = NULL;
          free_chain ((GstPlayChain *) playsink->audiochain);
          playsink->audiochain = NULL;
          playsink->volume_changed = playsink->mute_changed = FALSE;
      }
  
      if (!playsink->audio_sinkpad_stream_synchronizer) {
 +      GValue item = { 0, };
        GstIterator *it;
  
        playsink->audio_sinkpad_stream_synchronizer =
        it = gst_pad_iterate_internal_links
            (playsink->audio_sinkpad_stream_synchronizer);
        g_assert (it);
 -      gst_iterator_next (it,
 -          (gpointer *) & playsink->audio_srcpad_stream_synchronizer);
 +      gst_iterator_next (it, &item);
 +      playsink->audio_srcpad_stream_synchronizer = g_value_dup_object (&item);
 +      g_value_unset (&item);
        g_assert (playsink->audio_srcpad_stream_synchronizer);
        gst_iterator_free (it);
      }
          disconnect_chain (playsink->audiochain, playsink);
          playsink->audiochain->volume = NULL;
          playsink->audiochain->mute = NULL;
-         gst_object_replace ((GstObject **) & playsink->audiochain->ts_offset,
-             NULL);
+         if (playsink->audiochain->ts_offset)
+           gst_object_unref (playsink->audiochain->ts_offset);
+         playsink->audiochain->ts_offset = NULL;
        }
        add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
        activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
        add_chain (GST_PLAY_CHAIN (playsink->textchain), TRUE);
  
        if (!playsink->text_sinkpad_stream_synchronizer) {
 +        GValue item = { 0, };
 +
          playsink->text_sinkpad_stream_synchronizer =
              gst_element_get_request_pad (GST_ELEMENT_CAST
              (playsink->stream_synchronizer), "sink_%d");
          it = gst_pad_iterate_internal_links
              (playsink->text_sinkpad_stream_synchronizer);
          g_assert (it);
 -        gst_iterator_next (it,
 -            (gpointer *) & playsink->text_srcpad_stream_synchronizer);
 +        gst_iterator_next (it, &item);
 +        playsink->text_srcpad_stream_synchronizer = g_value_dup_object (&item);
 +        g_value_unset (&item);
          g_assert (playsink->text_srcpad_stream_synchronizer);
          gst_iterator_free (it);
  
@@@ -2817,8 -2814,7 +2820,8 @@@ gst_play_sink_convert_frame (GstPlaySin
      GstBuffer *temp;
      GError *err = NULL;
  
 -    temp = gst_video_convert_frame (result, caps, 25 * GST_SECOND, &err);
 +    /* FIXME, need to get the input buffer caps */
 +    temp = gst_video_convert_frame (result, NULL, caps, 25 * GST_SECOND, &err);
      gst_buffer_unref (result);
      if (temp == NULL && err) {
        /* I'm really uncertain whether we should make playsink post an error
@@@ -2838,8 -2834,8 +2841,8 @@@ is_raw_structure (GstStructure * s
  
    name = gst_structure_get_name (s);
  
 -  if (g_str_has_prefix (name, "video/x-raw-") ||
 -      g_str_has_prefix (name, "audio/x-raw-"))
 +  if (g_str_has_prefix (name, "video/x-raw") ||
 +      g_str_has_prefix (name, "audio/x-raw"))
      return TRUE;
    return FALSE;
  }
@@@ -2854,11 -2850,11 +2857,11 @@@ is_raw_pad (GstPad * pad
    if (!peer)
      return raw;
  
 -  caps = gst_pad_get_negotiated_caps (peer);
 +  caps = gst_pad_get_current_caps (peer);
    if (!caps) {
      guint i, n;
  
 -    caps = gst_pad_get_caps_reffed (peer);
 +    caps = gst_pad_get_caps (peer, NULL);
  
      n = gst_caps_get_size (caps);
      for (i = 0; i < n; i++) {
    return raw;
  }
  
 +static GstProbeReturn
 +sinkpad_blocked_cb (GstPad * blockedpad, GstProbeType type, gpointer type_data,
 +    gpointer user_data);
 +
  static void
 -sinkpad_blocked_cb (GstPad * blockedpad, gboolean blocked, gpointer user_data)
 +video_set_blocked (GstPlaySink * playsink, gboolean blocked)
 +{
 +  if (playsink->video_pad) {
 +    GstPad *opad =
 +        GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 +            (playsink->video_pad)));
 +    if (blocked && playsink->video_block_id == 0) {
 +      playsink->video_block_id =
 +          gst_pad_add_probe (opad, GST_PROBE_TYPE_BLOCK, sinkpad_blocked_cb,
 +          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 +    } else if (!blocked && playsink->video_block_id) {
 +      gst_pad_remove_probe (opad, playsink->video_block_id);
 +      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_VIDEO_RAW);
 +      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_VIDEO);
 +      playsink->video_block_id = 0;
 +      playsink->video_pad_blocked = FALSE;
 +    }
 +    gst_object_unref (opad);
 +  }
 +}
 +
 +static void
 +audio_set_blocked (GstPlaySink * playsink, gboolean blocked)
 +{
 +  if (playsink->audio_pad) {
 +    GstPad *opad =
 +        GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 +            (playsink->audio_pad)));
 +    if (blocked && playsink->audio_block_id == 0) {
 +      playsink->audio_block_id =
 +          gst_pad_add_probe (opad, GST_PROBE_TYPE_BLOCK, sinkpad_blocked_cb,
 +          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 +    } else if (!blocked && playsink->audio_block_id) {
 +      gst_pad_remove_probe (opad, playsink->audio_block_id);
 +      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_AUDIO_RAW);
 +      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_AUDIO);
 +      playsink->audio_block_id = 0;
 +      playsink->audio_pad_blocked = FALSE;
 +    }
 +    gst_object_unref (opad);
 +  }
 +}
 +
 +static void
 +text_set_blocked (GstPlaySink * playsink, gboolean blocked)
 +{
 +  if (playsink->text_pad) {
 +    GstPad *opad =
 +        GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 +            (playsink->text_pad)));
 +    if (blocked && playsink->text_block_id == 0) {
 +      playsink->text_block_id =
 +          gst_pad_add_probe (opad, GST_PROBE_TYPE_BLOCK, sinkpad_blocked_cb,
 +          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 +    } else if (!blocked && playsink->text_block_id) {
 +      gst_pad_remove_probe (opad, playsink->text_block_id);
 +      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_TEXT);
 +      playsink->text_block_id = 0;
 +      playsink->text_pad_blocked = FALSE;
 +    }
 +    gst_object_unref (opad);
 +  }
 +}
 +
 +static GstProbeReturn
 +sinkpad_blocked_cb (GstPad * blockedpad, GstProbeType type, gpointer type_data,
 +    gpointer user_data)
  {
    GstPlaySink *playsink = (GstPlaySink *) user_data;
    GstPad *pad;
  
    pad = GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (blockedpad)));
    if (pad == playsink->video_pad) {
 -    playsink->video_pad_blocked = blocked;
 -    GST_DEBUG_OBJECT (pad, "Video pad blocked: %d", blocked);
 -    if (!blocked) {
 -      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_VIDEO_RAW);
 -      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_VIDEO);
 -    }
 +    playsink->video_pad_blocked = TRUE;
 +    GST_DEBUG_OBJECT (pad, "Video pad blocked");
    } else if (pad == playsink->audio_pad) {
 -    playsink->audio_pad_blocked = blocked;
 -    GST_DEBUG_OBJECT (pad, "Audio pad blocked: %d", blocked);
 -    if (!blocked) {
 -      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_AUDIO_RAW);
 -      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_AUDIO);
 -    }
 +    playsink->audio_pad_blocked = TRUE;
 +    GST_DEBUG_OBJECT (pad, "Audio pad blocked");
    } else if (pad == playsink->text_pad) {
 -    playsink->text_pad_blocked = blocked;
 -    GST_DEBUG_OBJECT (pad, "Text pad blocked: %d", blocked);
 -    if (!blocked)
 -      PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_TEXT);
 -  }
 -
 -  if (!blocked) {
 -    gst_object_unref (pad);
 -    GST_PLAY_SINK_UNLOCK (playsink);
 -    return;
 +    playsink->text_pad_blocked = TRUE;
 +    GST_DEBUG_OBJECT (pad, "Text pad blocked");
    }
  
    /* We reconfigure when for ALL streams:
  
      gst_play_sink_reconfigure (playsink);
  
 -    if (playsink->video_pad) {
 -      GstPad *opad =
 -          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 -              (playsink->video_pad)));
 -      gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
 -          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 -      gst_object_unref (opad);
 -    }
 -
 -    if (playsink->audio_pad) {
 -      GstPad *opad =
 -          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 -              (playsink->audio_pad)));
 -      gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
 -          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 -      gst_object_unref (opad);
 -    }
 -
 -    if (playsink->text_pad) {
 -      GstPad *opad =
 -          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 -              (playsink->text_pad)));
 -      gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
 -          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 -      gst_object_unref (opad);
 -    }
 +    video_set_blocked (playsink, FALSE);
 +    audio_set_blocked (playsink, FALSE);
 +    text_set_blocked (playsink, FALSE);
    }
  
    gst_object_unref (pad);
  
    GST_PLAY_SINK_UNLOCK (playsink);
 +
 +  return GST_PROBE_OK;
  }
  
  static void
@@@ -3024,14 -2987,14 +3027,14 @@@ caps_notify_cb (GstPad * pad, GParamSpe
  
    if (pad == playsink->audio_pad) {
      raw = is_raw_pad (pad);
 -    reconfigure = (! !playsink->audio_pad_raw != ! !raw)
 +    reconfigure = (!!playsink->audio_pad_raw != !!raw)
          && playsink->audiochain;
      GST_DEBUG_OBJECT (pad,
          "Audio caps changed: raw %d reconfigure %d caps %" GST_PTR_FORMAT, raw,
          reconfigure, caps);
    } else if (pad == playsink->video_pad) {
      raw = is_raw_pad (pad);
 -    reconfigure = (! !playsink->video_pad_raw != ! !raw)
 +    reconfigure = (!!playsink->video_pad_raw != !!raw)
          && playsink->videochain;
      GST_DEBUG_OBJECT (pad,
          "Video caps changed: raw %d reconfigure %d caps %" GST_PTR_FORMAT, raw,
  
    if (reconfigure) {
      GST_PLAY_SINK_LOCK (playsink);
 -    if (playsink->video_pad) {
 -      GstPad *opad =
 -          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 -              (playsink->video_pad)));
 -      gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb,
 -          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 -      gst_object_unref (opad);
 -    }
 -
 -    if (playsink->audio_pad) {
 -      GstPad *opad =
 -          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 -              (playsink->audio_pad)));
 -      gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb,
 -          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 -      gst_object_unref (opad);
 -    }
 -
 -    if (playsink->text_pad) {
 -      GstPad *opad =
 -          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 -              (playsink->text_pad)));
 -      gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb,
 -          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 -      gst_object_unref (opad);
 -    }
 +    video_set_blocked (playsink, TRUE);
 +    audio_set_blocked (playsink, TRUE);
 +    text_set_blocked (playsink, TRUE);
      GST_PLAY_SINK_UNLOCK (playsink);
    }
  }
@@@ -3065,7 -3051,6 +3068,7 @@@ gst_play_sink_request_pad (GstPlaySink 
    gboolean created = FALSE;
    gboolean activate = TRUE;
    const gchar *pad_name = NULL;
 +  gulong *block_id = NULL;
  
    GST_DEBUG_OBJECT (playsink, "request pad type %d", type);
  
        }
        playsink->audio_pad_raw = FALSE;
        res = playsink->audio_pad;
 +      block_id = &playsink->audio_block_id;
        break;
      case GST_PLAY_SINK_TYPE_VIDEO_RAW:
      case GST_PLAY_SINK_TYPE_VIDEO:
        }
        playsink->video_pad_raw = FALSE;
        res = playsink->video_pad;
 +      block_id = &playsink->video_block_id;
        break;
      case GST_PLAY_SINK_TYPE_TEXT:
        GST_LOG_OBJECT (playsink, "ghosting text");
          created = TRUE;
        }
        res = playsink->text_pad;
 +      block_id = &playsink->text_block_id;
        break;
      case GST_PLAY_SINK_TYPE_FLUSHING:
      {
       * element is 'running' */
      gst_pad_set_active (res, TRUE);
      gst_element_add_pad (GST_ELEMENT_CAST (playsink), res);
 -    if (type != GST_PLAY_SINK_TYPE_FLUSHING) {
 +    if (block_id && *block_id == 0) {
        GstPad *blockpad =
            GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (res)));
  
 -      gst_pad_set_blocked_async_full (blockpad, TRUE, sinkpad_blocked_cb,
 +      *block_id =
 +          gst_pad_add_probe (blockpad, GST_PROBE_TYPE_BLOCK, sinkpad_blocked_cb,
            gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
        PENDING_FLAG_SET (playsink, type);
        gst_object_unref (blockpad);
  
  static GstPad *
  gst_play_sink_request_new_pad (GstElement * element, GstPadTemplate * templ,
 -    const gchar * name)
 +    const gchar * name, const GstCaps * caps)
  {
    GstPlaySink *psink;
    GstPad *pad;
@@@ -3410,9 -3391,42 +3413,9 @@@ gst_play_sink_change_state (GstElement 
      case GST_STATE_CHANGE_PAUSED_TO_READY:
        /* unblock all pads here */
        GST_PLAY_SINK_LOCK (playsink);
 -      if (playsink->video_pad) {
 -        GstPad *opad =
 -            GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 -                (playsink->video_pad)));
 -        if (gst_pad_is_blocked (opad)) {
 -          gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
 -              gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 -        }
 -        gst_object_unref (opad);
 -        playsink->video_pad_blocked = FALSE;
 -      }
 -
 -      if (playsink->audio_pad) {
 -        GstPad *opad =
 -            GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 -                (playsink->audio_pad)));
 -
 -        if (gst_pad_is_blocked (opad)) {
 -          gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
 -              gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 -        }
 -        gst_object_unref (opad);
 -        playsink->audio_pad_blocked = FALSE;
 -      }
 -
 -      if (playsink->text_pad) {
 -        GstPad *opad =
 -            GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
 -                (playsink->text_pad)));
 -        if (gst_pad_is_blocked (opad)) {
 -          gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
 -              gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
 -        }
 -        gst_object_unref (opad);
 -        playsink->text_pad_blocked = FALSE;
 -      }
 +      video_set_blocked (playsink, FALSE);
 +      audio_set_blocked (playsink, FALSE);
 +      text_set_blocked (playsink, FALSE);
        GST_PLAY_SINK_UNLOCK (playsink);
        /* fall through */
      case GST_STATE_CHANGE_READY_TO_NULL:
          disconnect_chain (playsink->audiochain, playsink);
          playsink->audiochain->volume = NULL;
          playsink->audiochain->mute = NULL;
-         gst_object_replace ((GstObject **) & playsink->audiochain->ts_offset,
-             NULL);
+       }
+       if (playsink->audiochain && playsink->audiochain->ts_offset) {
+         gst_object_unref (playsink->audiochain->ts_offset);
+         playsink->audiochain->ts_offset = NULL;
+       }
+       if (playsink->videochain && playsink->videochain->ts_offset) {
+         gst_object_unref (playsink->videochain->ts_offset);
+         playsink->videochain->ts_offset = NULL;
        }
        ret = GST_STATE_CHANGE_SUCCESS;
        break;
@@@ -72,23 -72,46 +72,23 @@@ post_missing_element_message (GstPlaySi
    gst_element_post_message (GST_ELEMENT_CAST (self), msg);
  }
  
 -static void
 -distribute_running_time (GstElement * element, const GstSegment * segment)
 -{
 -  GstEvent *event;
 -  GstPad *pad;
 -
 -  pad = gst_element_get_static_pad (element, "sink");
 -
 -  if (segment->accum) {
 -    event = gst_event_new_new_segment_full (FALSE, segment->rate,
 -        segment->applied_rate, segment->format, 0, segment->accum, 0);
 -    gst_pad_send_event (pad, event);
 -  }
 -
 -  event = gst_event_new_new_segment_full (FALSE, segment->rate,
 -      segment->applied_rate, segment->format,
 -      segment->start, segment->stop, segment->time);
 -  gst_pad_send_event (pad, event);
 -
 -  gst_object_unref (pad);
 -}
 -
 -static void
 -pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self)
 +static GstProbeReturn
 +pad_blocked_cb (GstPad * pad, GstProbeType type, gpointer type_data,
 +    gpointer user_data)
  {
 +  GstPlaySinkVideoConvert *self = user_data;
    GstPad *peer;
    GstCaps *caps;
    gboolean raw;
  
    GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
 -  self->sink_proxypad_blocked = blocked;
 -  GST_DEBUG_OBJECT (self, "Pad blocked: %d", blocked);
 -  if (!blocked)
 -    goto done;
 +  GST_DEBUG_OBJECT (self, "Pad blocked");
  
    /* There must be a peer at this point */
    peer = gst_pad_get_peer (self->sinkpad);
 -  caps = gst_pad_get_negotiated_caps (peer);
 +  caps = gst_pad_get_current_caps (peer);
    if (!caps)
 -    caps = gst_pad_get_caps_reffed (peer);
 +    caps = gst_pad_get_caps (peer, NULL);
    gst_object_unref (peer);
  
    raw = is_raw_caps (caps);
      gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
      gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
  
-     self->conv = gst_element_factory_make ("videoconvert", "conv");
+     self->conv = gst_element_factory_make (COLORSPACE, "conv");
      if (self->conv == NULL) {
-       post_missing_element_message (self, "videoconvert");
+       post_missing_element_message (self, COLORSPACE);
        GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
            (_("Missing element '%s' - check your GStreamer installation."),
-               "videoconvert"), ("video rendering might fail"));
+               COLORSPACE), ("video rendering might fail"));
      } else {
        gst_bin_add (bin, self->conv);
        gst_element_sync_state_with_parent (self->conv);
 -      distribute_running_time (self->conv, &self->segment);
        prev = head = self->conv;
      }
  
        g_object_set (self->scale, "add-borders", TRUE, NULL);
        gst_bin_add (bin, self->scale);
        gst_element_sync_state_with_parent (self->scale);
 -      distribute_running_time (self->scale, &self->segment);
        if (prev) {
          if (!gst_element_link_pads_full (prev, "src", self->scale, "sink",
                  GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
    }
  
  unblock:
 -  gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
 -      (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
 -      (GDestroyNotify) gst_object_unref);
 -
 -done:
 +  self->sink_proxypad_block_id = 0;
    GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
 -  return;
 +
 +  return GST_PROBE_REMOVE;
  
  link_failed:
    {
          (NULL), ("Failed to configure the video converter."));
      gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
          self->sink_proxypad);
 -    gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
 -        (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 -
 +    self->sink_proxypad_block_id = 0;
      GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
 -    return;
 +
 +    return GST_PROBE_REMOVE;
    }
  }
  
 -static gboolean
 -gst_play_sink_video_convert_sink_event (GstPad * pad, GstEvent * event)
 +static void
 +block_proxypad (GstPlaySinkVideoConvert * self)
  {
 -  GstPlaySinkVideoConvert *self =
 -      GST_PLAY_SINK_VIDEO_CONVERT (gst_pad_get_parent (pad));
 -  gboolean ret;
 -
 -  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;
 -
 -    GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
 -    gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
 -        &format, &start, &stop, &position);
 -
 -    GST_DEBUG_OBJECT (self, "Segment before %" GST_SEGMENT_FORMAT,
 -        &self->segment);
 -    gst_segment_set_newsegment_full (&self->segment, update, rate, applied_rate,
 -        format, start, stop, position);
 -    GST_DEBUG_OBJECT (self, "Segment after %" GST_SEGMENT_FORMAT,
 -        &self->segment);
 -    GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
 -  } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
 -    GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
 -    GST_DEBUG_OBJECT (self, "Resetting segment");
 -    gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
 -    GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
 +  if (self->sink_proxypad_block_id == 0) {
 +    self->sink_proxypad_block_id =
 +        gst_pad_add_probe (self->sink_proxypad, GST_PROBE_TYPE_BLOCK,
 +        pad_blocked_cb, gst_object_ref (self),
 +        (GDestroyNotify) gst_object_unref);
    }
 +}
  
 -  gst_event_unref (event);
 -  gst_object_unref (self);
 -
 -  return ret;
 +static void
 +unblock_proxypad (GstPlaySinkVideoConvert * self)
 +{
 +  if (self->sink_proxypad_block_id != 0) {
 +    gst_pad_remove_probe (self->sink_proxypad, self->sink_proxypad_block_id);
 +    self->sink_proxypad_block_id = 0;
 +  }
  }
  
  static gboolean
 -gst_play_sink_video_convert_sink_setcaps (GstPad * pad, GstCaps * caps)
 +gst_play_sink_video_convert_sink_setcaps (GstPlaySinkVideoConvert * self,
 +    GstCaps * caps)
  {
 -  GstPlaySinkVideoConvert *self =
 -      GST_PLAY_SINK_VIDEO_CONVERT (gst_pad_get_parent (pad));
 -  gboolean ret;
    GstStructure *s;
    const gchar *name;
    gboolean reconfigure = FALSE;
    s = gst_caps_get_structure (caps, 0);
    name = gst_structure_get_name (s);
  
 -  if (g_str_has_prefix (name, "video/x-raw-")) {
 +  if (g_str_has_prefix (name, "video/x-raw")) {
      if (!self->raw && !gst_pad_is_blocked (self->sink_proxypad)) {
        GST_DEBUG_OBJECT (self, "Changing caps from non-raw to raw");
        reconfigure = TRUE;
 -      gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
 -          (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 +      block_proxypad (self);
      }
    } else {
      if (self->raw && !gst_pad_is_blocked (self->sink_proxypad)) {
        GST_DEBUG_OBJECT (self, "Changing caps from raw to non-raw");
        reconfigure = TRUE;
 -      gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
 -          (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 +      block_proxypad (self);
      }
    }
  
    }
    GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
  
 -  ret = gst_ghost_pad_setcaps_default (pad, caps);
 +  GST_DEBUG_OBJECT (self, "Setting sink caps %" GST_PTR_FORMAT, caps);
 +
 +  return TRUE;
 +}
 +
 +static gboolean
 +gst_play_sink_video_convert_sink_event (GstPad * pad, GstEvent * event)
 +{
 +  GstPlaySinkVideoConvert *self =
 +      GST_PLAY_SINK_VIDEO_CONVERT (gst_pad_get_parent (pad));
 +  gboolean ret;
 +
 +  switch (GST_EVENT_TYPE (event)) {
 +    case GST_EVENT_CAPS:
 +    {
 +      GstCaps *caps;
 +
 +      gst_event_parse_caps (event, &caps);
 +      ret = gst_play_sink_video_convert_sink_setcaps (self, caps);
 +      break;
 +    }
 +    default:
 +      break;
 +  }
 +
 +  ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
  
 -  GST_DEBUG_OBJECT (self, "Setting sink caps %" GST_PTR_FORMAT ": %d", caps,
 -      ret);
 +  switch (GST_EVENT_TYPE (event)) {
 +    case GST_EVENT_SEGMENT:
 +      GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
 +      GST_DEBUG_OBJECT (self, "Segment before %" GST_SEGMENT_FORMAT,
 +          &self->segment);
 +      gst_event_copy_segment (event, &self->segment);
 +      GST_DEBUG_OBJECT (self, "Segment after %" GST_SEGMENT_FORMAT,
 +          &self->segment);
 +      GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
 +      break;
 +    case GST_EVENT_FLUSH_STOP:
 +      GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
 +      GST_DEBUG_OBJECT (self, "Resetting segment");
 +      gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
 +      GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
 +      break;
 +    default:
 +      break;
 +  }
  
 +  gst_event_unref (event);
    gst_object_unref (self);
  
    return ret;
  }
  
  static GstCaps *
 -gst_play_sink_video_convert_getcaps (GstPad * pad)
 +gst_play_sink_video_convert_getcaps (GstPad * pad, GstCaps * filter)
  {
    GstPlaySinkVideoConvert *self =
        GST_PLAY_SINK_VIDEO_CONVERT (gst_pad_get_parent (pad));
  
    peer = gst_pad_get_peer (otherpad);
    if (peer) {
 -    ret = gst_pad_get_caps_reffed (peer);
 +    ret = gst_pad_get_caps (peer, filter);
      gst_object_unref (peer);
    } else {
 -    ret = gst_caps_new_any ();
 +    ret = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
    }
  
    gst_object_unref (otherpad);
@@@ -360,7 -372,10 +360,7 @@@ gst_play_sink_video_convert_change_stat
    switch (transition) {
      case GST_STATE_CHANGE_PAUSED_TO_READY:
        GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
 -      if (gst_pad_is_blocked (self->sink_proxypad))
 -        gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
 -            (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
 -            (GDestroyNotify) gst_object_unref);
 +      unblock_proxypad (self);
        GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
        break;
      default:
      case GST_STATE_CHANGE_READY_TO_PAUSED:
        GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
        if (!gst_pad_is_blocked (self->sink_proxypad))
 -        gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
 -            (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
 -            (GDestroyNotify) gst_object_unref);
 +        block_proxypad (self);
        GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
      default:
        break;
@@@ -441,6 -458,8 +441,6 @@@ gst_play_sink_video_convert_init (GstPl
    self->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", templ);
    gst_pad_set_event_function (self->sinkpad,
        GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_sink_event));
 -  gst_pad_set_setcaps_function (self->sinkpad,
 -      GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_sink_setcaps));
    gst_pad_set_getcaps_function (self->sinkpad,
        GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_getcaps));
  
@@@ -29,7 -29,7 +29,7 @@@
   * <refsect2>
   * <title>Examples</title>
   * |[
 - * gst-launch -v filesrc location=test.mkv ! matroskademux name=demux ! "video/x-h264" ! queue2 ! decodebin2 ! subtitleoverlay name=overlay ! ffmpegcolorspace ! autovideosink  demux. ! "video/x-dvd-subpicture" ! queue2 ! overlay.
 + * gst-launch -v filesrc location=test.mkv ! matroskademux name=demux ! "video/x-h264" ! queue2 ! decodebin ! subtitleoverlay name=overlay ! videoconvert ! autovideosink  demux. ! "video/x-dvd-subpicture" ! queue2 ! overlay.
   * ]| This will play back the given Matroska file with h264 video and subpicture subtitles.
   * </refsect2>
   */
@@@ -79,8 -79,11 +79,8 @@@ enu
    PROP_SUBTITLE_ENCODING
  };
  
 -GST_BOILERPLATE (GstSubtitleOverlay, gst_subtitle_overlay, GstBin,
 -    GST_TYPE_BIN);
 -
 -static void _pad_blocked_cb (GstPad * pad, gboolean blocked,
 -    gpointer user_data);
 +#define gst_subtitle_overlay_parent_class parent_class
 +G_DEFINE_TYPE (GstSubtitleOverlay, gst_subtitle_overlay, GST_TYPE_BIN);
  
  static GQuark _subtitle_overlay_event_marker_id = 0;
  
@@@ -88,10 -91,11 +88,10 @@@ static voi
  do_async_start (GstSubtitleOverlay * self)
  {
    if (!self->do_async) {
 -    GstMessage *msg =
 -        gst_message_new_async_start (GST_OBJECT_CAST (self), FALSE);
 +    GstMessage *msg = gst_message_new_async_start (GST_OBJECT_CAST (self));
  
      GST_DEBUG_OBJECT (self, "Posting async-start");
 -    parent_class->handle_message (GST_BIN_CAST (self), msg);
 +    GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (self), msg);
      self->do_async = TRUE;
    }
  }
@@@ -100,67 -104,14 +100,67 @@@ static voi
  do_async_done (GstSubtitleOverlay * self)
  {
    if (self->do_async) {
 -    GstMessage *msg = gst_message_new_async_done (GST_OBJECT_CAST (self));
 +    GstMessage *msg =
 +        gst_message_new_async_done (GST_OBJECT_CAST (self), FALSE);
  
      GST_DEBUG_OBJECT (self, "Posting async-done");
 -    parent_class->handle_message (GST_BIN_CAST (self), msg);
 +    GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (self), msg);
      self->do_async = FALSE;
    }
  }
  
 +static GstProbeReturn
 +_pad_blocked_cb (GstPad * pad, GstProbeType type, gpointer type_data,
 +    gpointer user_data);
 +
 +static void
 +block_video (GstSubtitleOverlay * self)
 +{
 +  if (self->video_block_id != 0)
 +    return;
 +
 +  if (self->video_block_pad) {
 +    self->video_block_id =
 +        gst_pad_add_probe (self->video_block_pad, GST_PROBE_TYPE_BLOCK,
 +        _pad_blocked_cb, gst_object_ref (self),
 +        (GDestroyNotify) gst_object_unref);
 +  }
 +}
 +
 +static void
 +unblock_video (GstSubtitleOverlay * self)
 +{
 +  if (self->video_block_id) {
 +    gst_pad_remove_probe (self->video_block_pad, self->video_block_id);
 +    self->video_sink_blocked = FALSE;
 +    self->video_block_id = 0;
 +  }
 +}
 +
 +static void
 +block_subtitle (GstSubtitleOverlay * self)
 +{
 +  if (self->subtitle_block_id != 0)
 +    return;
 +
 +  if (self->subtitle_block_pad) {
 +    self->subtitle_block_id =
 +        gst_pad_add_probe (self->subtitle_block_pad, GST_PROBE_TYPE_BLOCK,
 +        _pad_blocked_cb, gst_object_ref (self),
 +        (GDestroyNotify) gst_object_unref);
 +  }
 +}
 +
 +static void
 +unblock_subtitle (GstSubtitleOverlay * self)
 +{
 +  if (self->subtitle_block_id) {
 +    gst_pad_remove_probe (self->subtitle_block_pad, self->subtitle_block_id);
 +    self->subtitle_sink_blocked = FALSE;
 +    self->subtitle_block_id = 0;
 +  }
 +}
 +
  static void
  gst_subtitle_overlay_finalize (GObject * object)
  {
@@@ -544,16 -495,26 +544,16 @@@ _remove_element (GstSubtitleOverlay * s
  }
  
  static void
 -_generate_update_newsegment_event (GstSegment * segment, GstEvent ** event1,
 -    GstEvent ** event2)
 +_generate_update_segment_event (GstSegment * segment, GstEvent ** event1)
  {
    GstEvent *event;
 +  GstStructure *structure;
  
 -  *event1 = NULL;
 -  *event2 = NULL;
 -
 -  event = gst_event_new_new_segment_full (FALSE, segment->rate,
 -      segment->applied_rate, segment->format, 0, segment->accum, 0);
 -  gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
 +  event = gst_event_new_segment (segment);
 +  structure = gst_event_writable_structure (event);
 +  gst_structure_id_set (structure, _subtitle_overlay_event_marker_id,
        G_TYPE_BOOLEAN, TRUE, NULL);
    *event1 = event;
 -
 -  event = gst_event_new_new_segment_full (FALSE, segment->rate,
 -      segment->applied_rate, segment->format,
 -      segment->start, segment->stop, segment->time);
 -  gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
 -      G_TYPE_BOOLEAN, TRUE, NULL);
 -  *event2 = event;
  }
  
  static gboolean
@@@ -617,12 -578,17 +617,12 @@@ _setup_passthrough (GstSubtitleOverlay 
    /* Send segment to the identity. This is dropped because identity
     * is not linked downstream yet */
    if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
 -    GstEvent *event1, *event2;
 +    GstEvent *event1;
  
 -    _generate_update_newsegment_event (&self->video_segment, &event1, &event2);
 -    GST_DEBUG_OBJECT (self,
 -        "Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
 -        event1->structure);
 +    _generate_update_segment_event (&self->video_segment, &event1);
      GST_DEBUG_OBJECT (self,
 -        "Pushing video update newsegment event: %" GST_PTR_FORMAT,
 -        event2->structure);
 +        "Pushing video segment event: %" GST_PTR_FORMAT, event1);
      gst_pad_send_event (sink, event1);
 -    gst_pad_send_event (sink, event2);
    }
  
    /* Link sink ghostpads to identity */
  
  out:
    /* Unblock pads */
 -  gst_pad_set_blocked_async_full (self->video_block_pad, FALSE,
 -      _pad_blocked_cb, gst_object_ref (self),
 -      (GDestroyNotify) gst_object_unref);
 -
 -  if (self->subtitle_sink_blocked)
 -    gst_pad_set_blocked_async_full (self->subtitle_block_pad, FALSE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 +  unblock_video (self);
 +  unblock_subtitle (self);
  
    return TRUE;
  }
@@@ -711,21 -683,25 +711,21 @@@ _has_font_desc_property (GstElement * e
    return (pspec && pspec->value_type == G_TYPE_STRING);
  }
  
 -static void
 -_pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
 +static GstProbeReturn
 +_pad_blocked_cb (GstPad * pad, GstProbeType type, gpointer type_data,
 +    gpointer user_data)
  {
    GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY_CAST (user_data);
    GstCaps *subcaps;
    GList *l, *factories = NULL;
  
 -  GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
 +  GST_DEBUG_OBJECT (pad, "Pad blocked");
  
    GST_SUBTITLE_OVERLAY_LOCK (self);
    if (pad == self->video_block_pad)
 -    self->video_sink_blocked = blocked;
 +    self->video_sink_blocked = TRUE;
    else if (pad == self->subtitle_block_pad)
 -    self->subtitle_sink_blocked = blocked;
 -
 -  if (!blocked) {
 -    GST_SUBTITLE_OVERLAY_UNLOCK (self);
 -    return;
 -  }
 +    self->subtitle_sink_blocked = TRUE;
  
    /* Now either both or the video sink are blocked */
  
  
      peer = gst_pad_get_peer (self->subtitle_sinkpad);
      if (peer) {
 -      subcaps = gst_pad_get_negotiated_caps (peer);
 +      subcaps = gst_pad_get_current_caps (peer);
        if (!subcaps) {
 -        subcaps = gst_pad_get_caps_reffed (peer);
 +        subcaps = gst_pad_get_caps (peer, NULL);
          if (!gst_caps_is_fixed (subcaps)) {
            gst_caps_unref (subcaps);
            subcaps = NULL;
        gst_object_unref (target);
  
        /* Unblock pads */
 -      gst_pad_set_blocked_async_full (self->video_block_pad, FALSE,
 -          _pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 -
 -      if (self->subtitle_sink_blocked)
 -        gst_pad_set_blocked_async_full (self->subtitle_block_pad, FALSE,
 -            _pad_blocked_cb, gst_object_ref (self),
 -            (GDestroyNotify) gst_object_unref);
 +      unblock_video (self);
 +      unblock_subtitle (self);
 +
        goto out;
      } else if (target) {
        gst_object_unref (target);
  
    if (self->subtitle_sink_blocked && !self->video_sink_blocked) {
      GST_DEBUG_OBJECT (self, "Subtitle sink blocked but video not blocked");
 -    gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 +    block_video (self);
      goto out;
    }
  
        video_peer = gst_pad_get_peer (self->video_sinkpad);
        if (video_peer) {
          GstCaps *video_caps;
 -        gint fps_n, fps_d;
  
 -        video_caps = gst_pad_get_negotiated_caps (video_peer);
 +        video_caps = gst_pad_get_current_caps (video_peer);
          if (!video_caps) {
 -          video_caps = gst_pad_get_caps_reffed (video_peer);
 +          video_caps = gst_pad_get_caps (video_peer, NULL);
            if (!gst_caps_is_fixed (video_caps)) {
              gst_caps_unref (video_caps);
              video_caps = NULL;
            }
          }
  
 -        if (video_caps
 -            && gst_video_parse_caps_framerate (video_caps, &fps_n, &fps_d)) {
 -          if (self->fps_n != fps_n || self->fps_d != fps_d) {
 -            GST_DEBUG_OBJECT (self, "New video fps: %d/%d", fps_n, fps_d);
 -            self->fps_n = fps_n;
 -            self->fps_d = fps_d;
 +        if (video_caps) {
 +          GstVideoInfo info;
 +
 +          if (gst_video_info_from_caps (&info, video_caps)) {
 +            if (self->fps_n != info.fps_n || self->fps_d != info.fps_d) {
 +              GST_DEBUG_OBJECT (self, "New video fps: %d/%d", info.fps_n,
 +                  info.fps_d);
 +              self->fps_n = info.fps_n;
 +              self->fps_d = info.fps_d;
 +            }
            }
          }
  
        gst_object_unref (src);
  
        if (G_UNLIKELY (!_create_element (self, &self->post_colorspace,
-                   "videoconvert", NULL, "post-colorspace", FALSE))) {
+                   COLORSPACE, NULL, "post-colorspace", FALSE))) {
          continue;
        }
  
  
        sink = gst_element_get_static_pad (self->post_colorspace, "sink");
        if (G_UNLIKELY (!sink)) {
-         GST_WARNING_OBJECT (self, "Can't get sink pad from videoconvert");
+         GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
          gst_object_unref (src);
          continue;
        }
  
        if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
-         GST_WARNING_OBJECT (self, "Can't link overlay with videoconvert");
+         GST_WARNING_OBJECT (self, "Can't link overlay with " COLORSPACE);
          gst_object_unref (src);
          gst_object_unref (sink);
          continue;
        gst_object_unref (sink);
  
        if (G_UNLIKELY (!_create_element (self, &self->pre_colorspace,
-                   "videoconvert", NULL, "pre-colorspace", FALSE))) {
+                   COLORSPACE, NULL, "pre-colorspace", FALSE))) {
          continue;
        }
  
  
        src = gst_element_get_static_pad (self->pre_colorspace, "src");
        if (G_UNLIKELY (!src)) {
-         GST_WARNING_OBJECT (self, "Can't get srcpad from videoconvert");
+         GST_WARNING_OBJECT (self, "Can't get srcpad from " COLORSPACE);
          gst_object_unref (sink);
          continue;
        }
  
        if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
-         GST_WARNING_OBJECT (self, "Can't link videoconvert to textoverlay");
+         GST_WARNING_OBJECT (self, "Can't link " COLORSPACE " to textoverlay");
          gst_object_unref (src);
          gst_object_unref (sink);
          continue;
        /* Set src ghostpad target */
        src = gst_element_get_static_pad (self->post_colorspace, "src");
        if (G_UNLIKELY (!src)) {
-         GST_WARNING_OBJECT (self, "Can't get src pad from videoconvert");
+         GST_WARNING_OBJECT (self, "Can't get src pad from " COLORSPACE);
          continue;
        }
  
        /* Send segments to the parser/overlay if necessary. These are not sent
         * outside this element because of the proxy pad event function */
        if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
 -        GstEvent *event1, *event2;
 +        GstEvent *event1;
  
          sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
          if (G_UNLIKELY (!sink)) {
-           GST_WARNING_OBJECT (self, "Can't get sink pad from videoconvert");
+           GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
            continue;
          }
  
 -        _generate_update_newsegment_event (&self->video_segment, &event1,
 -            &event2);
 +        _generate_update_segment_event (&self->video_segment, &event1);
          GST_DEBUG_OBJECT (self,
 -            "Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
 -            event1->structure);
 -        GST_DEBUG_OBJECT (self,
 -            "Pushing video update newsegment event: %" GST_PTR_FORMAT,
 -            event2->structure);
 +            "Pushing video segment event: %" GST_PTR_FORMAT, event1);
          gst_pad_send_event (sink, event1);
 -        gst_pad_send_event (sink, event2);
  
          gst_object_unref (sink);
        }
  
        if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED) {
 -        GstEvent *event1, *event2;
 +        GstEvent *event1;
  
          sink = gst_element_get_static_pad (element, "sink");
          if (G_UNLIKELY (!sink)) {
            continue;
          }
  
 -        _generate_update_newsegment_event (&self->subtitle_segment, &event1,
 -            &event2);
 -        GST_DEBUG_OBJECT (self,
 -            "Pushing subtitle accumulate newsegment event: %" GST_PTR_FORMAT,
 -            event1->structure);
 +        _generate_update_segment_event (&self->subtitle_segment, &event1);
          GST_DEBUG_OBJECT (self,
 -            "Pushing subtitle update newsegment event: %" GST_PTR_FORMAT,
 -            event2->structure);
 +            "Pushing subtitle segment event: %" GST_PTR_FORMAT, event1);
          gst_pad_send_event (sink, event1);
 -        gst_pad_send_event (sink, event2);
  
          gst_object_unref (sink);
        }
        /* Set the sink ghostpad targets */
        sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
        if (G_UNLIKELY (!sink)) {
-         GST_WARNING_OBJECT (self, "Can't get sink pad from videoconvert");
+         GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
          continue;
        }
  
  
        /* First link everything internally */
        if (G_UNLIKELY (!_create_element (self, &self->post_colorspace,
-                   "videoconvert", NULL, "post-colorspace", FALSE))) {
+                   COLORSPACE, NULL, "post-colorspace", FALSE))) {
          continue;
        }
  
  
        sink = gst_element_get_static_pad (self->post_colorspace, "sink");
        if (G_UNLIKELY (!sink)) {
-         GST_WARNING_OBJECT (self, "Can't get sink pad from videoconvert");
+         GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
          gst_object_unref (src);
          continue;
        }
  
        if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
-         GST_WARNING_OBJECT (self, "Can't link renderer with videoconvert");
+         GST_WARNING_OBJECT (self, "Can't link renderer with " COLORSPACE);
          gst_object_unref (src);
          gst_object_unref (sink);
          continue;
        gst_object_unref (sink);
  
        if (G_UNLIKELY (!_create_element (self, &self->pre_colorspace,
-                   "videoconvert", NULL, "pre-colorspace", FALSE))) {
+                   COLORSPACE, NULL, "pre-colorspace", FALSE))) {
          continue;
        }
  
  
        src = gst_element_get_static_pad (self->pre_colorspace, "src");
        if (G_UNLIKELY (!src)) {
-         GST_WARNING_OBJECT (self, "Can't get srcpad from videoconvert");
+         GST_WARNING_OBJECT (self, "Can't get srcpad from " COLORSPACE);
          gst_object_unref (sink);
          continue;
        }
  
        if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
-         GST_WARNING_OBJECT (self, "Can't link videoconvert to renderer");
+         GST_WARNING_OBJECT (self, "Can't link " COLORSPACE " to renderer");
          gst_object_unref (src);
          gst_object_unref (sink);
          continue;
        /* Set src ghostpad target */
        src = gst_element_get_static_pad (self->post_colorspace, "src");
        if (G_UNLIKELY (!src)) {
-         GST_WARNING_OBJECT (self, "Can't get src pad from videoconvert");
+         GST_WARNING_OBJECT (self, "Can't get src pad from " COLORSPACE);
          continue;
        }
  
        /* Send segments to the renderer if necessary. These are not sent
         * outside this element because of the proxy pad event handler */
        if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
 -        GstEvent *event1, *event2;
 +        GstEvent *event1;
  
          sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
          if (G_UNLIKELY (!sink)) {
-           GST_WARNING_OBJECT (self, "Can't get sink pad from videoconvert");
+           GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
            continue;
          }
  
 -        _generate_update_newsegment_event (&self->video_segment, &event1,
 -            &event2);
 +        _generate_update_segment_event (&self->video_segment, &event1);
          GST_DEBUG_OBJECT (self,
 -            "Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
 -            event1->structure);
 -        GST_DEBUG_OBJECT (self,
 -            "Pushing video update newsegment event: %" GST_PTR_FORMAT,
 -            event2->structure);
 +            "Pushing video segment event: %" GST_PTR_FORMAT, event1);
          gst_pad_send_event (sink, event1);
 -        gst_pad_send_event (sink, event2);
          gst_object_unref (sink);
        }
  
        if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED) {
 -        GstEvent *event1, *event2;
 +        GstEvent *event1;
  
          sink = _get_sub_pad (element);
          if (G_UNLIKELY (!sink)) {
            continue;
          }
  
 -        _generate_update_newsegment_event (&self->subtitle_segment, &event1,
 -            &event2);
 -        GST_DEBUG_OBJECT (self,
 -            "Pushing subtitle accumulate newsegment event: %" GST_PTR_FORMAT,
 -            event1->structure);
 +        _generate_update_segment_event (&self->subtitle_segment, &event1);
          GST_DEBUG_OBJECT (self,
 -            "Pushing subtitle update newsegment event: %" GST_PTR_FORMAT,
 -            event2->structure);
 +            "Pushing subtitle segment event: %" GST_PTR_FORMAT, event1);
          gst_pad_send_event (sink, event1);
 -        gst_pad_send_event (sink, event2);
          gst_object_unref (sink);
        }
  
        /* Set the sink ghostpad targets */
        sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
        if (G_UNLIKELY (!sink)) {
-         GST_WARNING_OBJECT (self, "Can't get sink pad from videoconvert");
+         GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
          continue;
        }
  
      do_async_done (self);
    } else {
      GST_DEBUG_OBJECT (self, "Everything worked, unblocking pads");
 -    gst_pad_set_blocked_async_full (self->video_block_pad, FALSE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 -    gst_pad_set_blocked_async_full (self->subtitle_block_pad, FALSE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 +    unblock_video (self);
 +    unblock_subtitle (self);
      do_async_done (self);
    }
  
@@@ -1248,8 -1256,6 +1248,8 @@@ out
    if (factories)
      gst_plugin_feature_list_free (factories);
    GST_SUBTITLE_OVERLAY_UNLOCK (self);
 +
 +  return GST_PROBE_OK;
  }
  
  static GstStateChangeReturn
@@@ -1271,8 -1277,12 +1271,8 @@@ gst_subtitle_overlay_change_state (GstE
  
        GST_SUBTITLE_OVERLAY_LOCK (self);
        /* Set the internal pads to blocking */
 -      gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -          _pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 -      gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
 -          _pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 +      block_video (self);
 +      block_subtitle (self);
        GST_SUBTITLE_OVERLAY_UNLOCK (self);
        break;
      case GST_STATE_CHANGE_READY_TO_PAUSED:
        do_async_done (self);
  
        break;
 -    case GST_STATE_CHANGE_READY_TO_NULL:{
 -      GstPad *pad;
 -
 +    case GST_STATE_CHANGE_READY_TO_NULL:
        GST_DEBUG_OBJECT (self, "State change READY->NULL");
  
        GST_SUBTITLE_OVERLAY_LOCK (self);
            NULL);
  
        /* Unblock pads */
 -      if (self->video_block_pad) {
 -        pad = self->video_block_pad;
 -        gst_pad_set_blocked_async_full (pad, FALSE, _pad_blocked_cb,
 -            gst_object_ref (self), (GDestroyNotify) gst_object_unref);
 -      }
 -
 -      if (self->subtitle_block_pad) {
 -        pad = self->subtitle_block_pad;
 -        gst_pad_set_blocked_async_full (pad, FALSE, _pad_blocked_cb,
 -            gst_object_ref (self), (GDestroyNotify) gst_object_unref);
 -      }
 +      unblock_video (self);
 +      unblock_subtitle (self);
  
        /* Remove elements */
        self->silent_property = NULL;
        GST_SUBTITLE_OVERLAY_UNLOCK (self);
  
        break;
 -    }
      default:
        break;
    }
@@@ -1392,8 -1414,13 +1392,8 @@@ gst_subtitle_overlay_handle_message (Gs
        GST_SUBTITLE_OVERLAY_LOCK (self);
        self->subtitle_error = TRUE;
  
 -      gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
 -          _pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 -
 -      gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -          _pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 +      block_subtitle (self);
 +      block_video (self);
        GST_SUBTITLE_OVERLAY_UNLOCK (self);
      }
    }
@@@ -1448,8 -1475,13 +1448,8 @@@ gst_subtitle_overlay_set_property (GObj
          else if (self->renderer)
            g_object_set (self->renderer, self->silent_property, silent, NULL);
        } else {
 -        gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
 -            _pad_blocked_cb, gst_object_ref (self),
 -            (GDestroyNotify) gst_object_unref);
 -
 -        gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -            _pad_blocked_cb, gst_object_ref (self),
 -            (GDestroyNotify) gst_object_unref);
 +        block_subtitle (self);
 +        block_video (self);
        }
        GST_SUBTITLE_OVERLAY_UNLOCK (self);
        break;
  }
  
  static void
 -gst_subtitle_overlay_base_init (gpointer g_class)
 -{
 -  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
 -
 -  gst_element_class_add_pad_template (gstelement_class,
 -      gst_static_pad_template_get (&srctemplate));
 -
 -  gst_element_class_add_pad_template (gstelement_class,
 -      gst_static_pad_template_get (&video_sinktemplate));
 -  gst_element_class_add_pad_template (gstelement_class,
 -      gst_static_pad_template_get (&subtitle_sinktemplate));
 -
 -  gst_element_class_set_details_simple (gstelement_class, "Subtitle Overlay",
 -      "Video/Overlay/Subtitle",
 -      "Overlays a video stream with subtitles",
 -      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
 -}
 -
 -static void
  gst_subtitle_overlay_class_init (GstSubtitleOverlayClass * klass)
  {
    GObjectClass *gobject_class = (GObjectClass *) klass;
            "ISO-8859-15 will be assumed.", NULL,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
 +  gst_element_class_add_pad_template (element_class,
 +      gst_static_pad_template_get (&srctemplate));
 +
 +  gst_element_class_add_pad_template (element_class,
 +      gst_static_pad_template_get (&video_sinktemplate));
 +  gst_element_class_add_pad_template (element_class,
 +      gst_static_pad_template_get (&subtitle_sinktemplate));
 +
 +  gst_element_class_set_details_simple (element_class, "Subtitle Overlay",
 +      "Video/Overlay/Subtitle",
 +      "Overlays a video stream with subtitles",
 +      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
 +
    element_class->change_state =
        GST_DEBUG_FUNCPTR (gst_subtitle_overlay_change_state);
  
@@@ -1583,7 -1621,7 +1583,7 @@@ gst_subtitle_overlay_src_proxy_event (G
    s = gst_event_get_structure (event);
    if (s && gst_structure_id_has_field (s, _subtitle_overlay_event_marker_id)) {
      GST_DEBUG_OBJECT (ghostpad, "Dropping event with marker: %" GST_PTR_FORMAT,
 -        event->structure);
 +        event);
      gst_event_unref (event);
      event = NULL;
      ret = TRUE;
  }
  
  static gboolean
 -gst_subtitle_overlay_video_sink_setcaps (GstPad * pad, GstCaps * caps)
 +gst_subtitle_overlay_video_sink_setcaps (GstSubtitleOverlay * self,
 +    GstCaps * caps)
  {
 -  GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
    gboolean ret = TRUE;
 -  gint fps_n, fps_d;
 +  GstVideoInfo info;
  
 -  GST_DEBUG_OBJECT (pad, "Setting caps: %" GST_PTR_FORMAT, caps);
 +  GST_DEBUG_OBJECT (self, "Setting caps: %" GST_PTR_FORMAT, caps);
  
 -  if (!gst_video_parse_caps_framerate (caps, &fps_n, &fps_d)) {
 -    GST_ERROR_OBJECT (pad, "Failed to parse framerate from caps");
 +  if (!gst_video_info_from_caps (&info, caps)) {
 +    GST_ERROR_OBJECT (self, "Failed to parse caps");
      ret = FALSE;
      goto out;
    }
  
    GST_SUBTITLE_OVERLAY_LOCK (self);
 -  if (self->fps_n != fps_n || self->fps_d != fps_d) {
 -    GST_DEBUG_OBJECT (self, "New video fps: %d/%d", fps_n, fps_d);
 -    self->fps_n = fps_n;
 -    self->fps_d = fps_d;
 +  if (self->fps_n != info.fps_n || self->fps_d != info.fps_d) {
 +    GST_DEBUG_OBJECT (self, "New video fps: %d/%d", info.fps_n, info.fps_d);
 +    self->fps_n = info.fps_n;
 +    self->fps_d = info.fps_d;
      gst_subtitle_overlay_set_fps (self);
    }
    GST_SUBTITLE_OVERLAY_UNLOCK (self);
  
 -  ret = gst_ghost_pad_setcaps_default (pad, caps);
 -
  out:
 -  gst_object_unref (self);
    return ret;
  }
  
@@@ -1636,53 -1677,45 +1636,53 @@@ gst_subtitle_overlay_video_sink_event (
    GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
    gboolean ret;
  
 -  if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
 -    GST_DEBUG_OBJECT (pad,
 -        "Resetting video segment because of flush-stop event");
 -    gst_segment_init (&self->video_segment, GST_FORMAT_UNDEFINED);
 -    self->fps_n = self->fps_d = 0;
 +  switch (GST_EVENT_TYPE (event)) {
 +    case GST_EVENT_FLUSH_STOP:
 +    {
 +      GST_DEBUG_OBJECT (pad,
 +          "Resetting video segment because of flush-stop event");
 +      gst_segment_init (&self->video_segment, GST_FORMAT_UNDEFINED);
 +      self->fps_n = self->fps_d = 0;
 +      break;
 +    }
 +    case GST_EVENT_CAPS:
 +    {
 +      GstCaps *caps;
 +
 +      gst_event_parse_caps (event, &caps);
 +      ret = gst_subtitle_overlay_video_sink_setcaps (self, caps);
 +      if (!ret)
 +        goto done;
 +      break;
 +    }
 +    default:
 +      break;
    }
  
    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;
 -
 -    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);
 -
 -    if (format != GST_FORMAT_TIME) {
 -      GST_ERROR_OBJECT (pad, "Newsegment event in non-time format: %s",
 -          gst_format_get_name (format));
 -      gst_object_unref (event);
 -      gst_object_unref (self);
 -      return FALSE;
 -    }
 +  if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
 +    GST_DEBUG_OBJECT (pad, "segment event: %" GST_PTR_FORMAT, event);
 +    gst_event_copy_segment (event, &self->video_segment);
  
 -    GST_DEBUG_OBJECT (pad, "Old video segment: %" GST_SEGMENT_FORMAT,
 -        &self->video_segment);
 -    gst_segment_set_newsegment_full (&self->video_segment, update, rate,
 -        applied_rate, format, start, stop, position);
 -    GST_DEBUG_OBJECT (pad, "New video segment: %" GST_SEGMENT_FORMAT,
 -        &self->video_segment);
 +    if (self->video_segment.format != GST_FORMAT_TIME)
 +      goto invalid_format;
    }
  
 +done:
    gst_event_unref (event);
    gst_object_unref (self);
 +
    return ret;
 +
 +  /* ERRORS */
 +invalid_format:
 +  {
 +    GST_ERROR_OBJECT (pad, "Newsegment event in non-time format: %s",
 +        gst_format_get_name (self->video_segment.format));
 +    ret = FALSE;
 +    goto done;
 +  }
  }
  
  static GstFlowReturn
@@@ -1698,8 -1731,13 +1698,8 @@@ gst_subtitle_overlay_video_sink_chain (
          gst_flow_get_name (ret));
      GST_SUBTITLE_OVERLAY_LOCK (self);
      self->subtitle_error = TRUE;
 -    gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 -
 -    gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 +    block_subtitle (self);
 +    block_video (self);
      GST_SUBTITLE_OVERLAY_UNLOCK (self);
  
      return GST_FLOW_OK;
@@@ -1724,8 -1762,13 +1724,8 @@@ gst_subtitle_overlay_subtitle_sink_chai
            gst_flow_get_name (ret));
        GST_SUBTITLE_OVERLAY_LOCK (self);
        self->subtitle_error = TRUE;
 -      gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
 -          _pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 -
 -      gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -          _pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 +      block_subtitle (self);
 +      block_video (self);
        GST_SUBTITLE_OVERLAY_UNLOCK (self);
  
        return GST_FLOW_OK;
  }
  
  static GstCaps *
 -gst_subtitle_overlay_subtitle_sink_getcaps (GstPad * pad)
 +gst_subtitle_overlay_subtitle_sink_getcaps (GstPad * pad, GstCaps * filter)
  {
    GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
    GstCaps *ret;
    g_mutex_lock (self->factories_lock);
    if (G_UNLIKELY (!gst_subtitle_overlay_update_factory_list (self)))
      ret = GST_CAPS_NONE;
 +  else if (filter)
 +    ret =
 +        gst_caps_intersect_full (filter, self->factory_caps,
 +        GST_CAPS_INTERSECT_FIRST);
    else
      ret = gst_caps_ref (self->factory_caps);
    g_mutex_unlock (self->factories_lock);
  static gboolean
  gst_subtitle_overlay_subtitle_sink_acceptcaps (GstPad * pad, GstCaps * caps)
  {
 -  GstCaps *othercaps = gst_subtitle_overlay_subtitle_sink_getcaps (pad);
 +  GstCaps *othercaps = gst_subtitle_overlay_subtitle_sink_getcaps (pad, NULL);
    gboolean ret = gst_caps_can_intersect (caps, othercaps);
  
    gst_caps_unref (othercaps);
  }
  
  static gboolean
 -gst_subtitle_overlay_subtitle_sink_setcaps (GstPad * pad, GstCaps * caps)
 +gst_subtitle_overlay_subtitle_sink_setcaps (GstSubtitleOverlay * self,
 +    GstCaps * caps)
  {
 -  GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
    gboolean ret = TRUE;
    GstPad *target = NULL;;
  
 -  GST_DEBUG_OBJECT (pad, "Setting caps: %" GST_PTR_FORMAT, caps);
 +  GST_DEBUG_OBJECT (self, "Setting caps: %" GST_PTR_FORMAT, caps);
  
    target =
        gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (self->subtitle_sinkpad));
    gst_caps_replace (&self->subcaps, caps);
  
    if (target && gst_pad_accept_caps (target, caps)) {
 -    GST_DEBUG_OBJECT (pad, "Target accepts caps");
 -    ret = gst_ghost_pad_setcaps_default (pad, caps);
 +    GST_DEBUG_OBJECT (self, "Target accepts caps");
      GST_SUBTITLE_OVERLAY_UNLOCK (self);
      goto out;
    }
  
 -  GST_DEBUG_OBJECT (pad, "Target did not accept caps");
 +  GST_DEBUG_OBJECT (self, "Target did not accept caps");
  
    self->subtitle_error = FALSE;
 -
 -  gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
 -      _pad_blocked_cb, gst_object_ref (self),
 -      (GDestroyNotify) gst_object_unref);
 -
 -  gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -      _pad_blocked_cb, gst_object_ref (self),
 -      (GDestroyNotify) gst_object_unref);
 +  block_subtitle (self);
 +  block_video (self);
    GST_SUBTITLE_OVERLAY_UNLOCK (self);
  
  out:
    if (target)
      gst_object_unref (target);
 -  gst_object_unref (self);
 +
    return ret;
  }
  
@@@ -1814,9 -1860,9 +1814,9 @@@ gst_subtitle_overlay_subtitle_sink_lin
  
    GST_DEBUG_OBJECT (pad, "Linking pad to peer %" GST_PTR_FORMAT, peer);
  
 -  caps = gst_pad_get_negotiated_caps (peer);
 +  caps = gst_pad_get_current_caps (peer);
    if (!caps) {
 -    caps = gst_pad_get_caps_reffed (peer);
 +    caps = gst_pad_get_caps (peer, NULL);
      if (!gst_caps_is_fixed (caps)) {
        gst_caps_unref (caps);
        caps = NULL;
  
      self->subtitle_error = FALSE;
  
 -    gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 -
 -    gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 +    block_subtitle (self);
 +    block_video (self);
      GST_SUBTITLE_OVERLAY_UNLOCK (self);
      gst_caps_unref (caps);
    }
@@@ -1860,8 -1911,15 +1860,8 @@@ gst_subtitle_overlay_subtitle_sink_unli
    GST_SUBTITLE_OVERLAY_LOCK (self);
    self->subtitle_error = FALSE;
  
 -  if (self->subtitle_block_pad)
 -    gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 -
 -  if (self->video_block_pad)
 -    gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -        _pad_blocked_cb, gst_object_ref (self),
 -        (GDestroyNotify) gst_object_unref);
 +  block_subtitle (self);
 +  block_video (self);
    GST_SUBTITLE_OVERLAY_UNLOCK (self);
  
    gst_object_unref (self);
@@@ -1872,63 -1930,92 +1872,63 @@@ gst_subtitle_overlay_subtitle_sink_even
  {
    GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
    gboolean ret;
 -  GstFormat format;
  
    if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM_OOB &&
 -      event->structure
 -      && strcmp (gst_structure_get_name (event->structure),
 -          "subtitleoverlay-flush-subtitle") == 0) {
 +      gst_event_has_name (event, "subtitleoverlay-flush-subtitle")) {
      GST_DEBUG_OBJECT (pad, "Custom subtitle flush event");
      GST_SUBTITLE_OVERLAY_LOCK (self);
      self->subtitle_flush = TRUE;
      self->subtitle_error = FALSE;
 -    if (self->subtitle_block_pad)
 -      gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
 -          _pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 -    if (self->video_block_pad)
 -      gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
 -          _pad_blocked_cb, gst_object_ref (self),
 -          (GDestroyNotify) gst_object_unref);
 +    block_subtitle (self);
 +    block_video (self);
      GST_SUBTITLE_OVERLAY_UNLOCK (self);
  
      gst_event_unref (event);
      event = NULL;
      ret = TRUE;
      goto out;
 -  } else if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
 -    gst_event_parse_new_segment_full (event, NULL, NULL, NULL,
 -        &format, NULL, NULL, NULL);
 -    if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED &&
 -        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, GST_FORMAT_UNDEFINED);
 -    }
    }
  
    switch (GST_EVENT_TYPE (event)) {
 +    case GST_EVENT_CAPS:
 +    {
 +      GstCaps *caps;
 +
 +      gst_event_parse_caps (event, &caps);
 +      ret = gst_subtitle_overlay_subtitle_sink_setcaps (self, caps);
 +      if (!ret)
 +        goto out;
 +      break;
 +    }
      case GST_EVENT_FLUSH_STOP:
        GST_DEBUG_OBJECT (pad,
            "Resetting subtitle segment because of flush-stop");
        gst_segment_init (&self->subtitle_segment, GST_FORMAT_UNDEFINED);
        /* fall through */
      case GST_EVENT_FLUSH_START:
 -    case GST_EVENT_NEWSEGMENT:
 +    case GST_EVENT_SEGMENT:
      case GST_EVENT_EOS:
 +    {
 +      GstStructure *structure;
 +
        /* Add our event marker to make sure no events from here go ever outside
         * the element, they're only interesting for our internal elements */
 -      event =
 -          GST_EVENT_CAST (gst_mini_object_make_writable (GST_MINI_OBJECT_CAST
 -              (event)));
 -      if (!event->structure) {
 -        event->structure =
 -            gst_structure_id_empty_new (_subtitle_overlay_event_marker_id);
 -        gst_structure_set_parent_refcount (event->structure,
 -            &event->mini_object.refcount);
 -      }
 -      gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
 +      event = GST_EVENT_CAST (gst_event_make_writable (event));
 +      structure = gst_event_writable_structure (event);
 +
 +      gst_structure_id_set (structure, _subtitle_overlay_event_marker_id,
            G_TYPE_BOOLEAN, TRUE, NULL);
        break;
 +    }
      default:
        break;
    }
  
    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_copy_segment (event, &self->subtitle_segment);
      GST_DEBUG_OBJECT (pad, "New subtitle segment: %" GST_SEGMENT_FORMAT,
          &self->subtitle_segment);
    }
@@@ -1940,7 -2027,8 +1940,7 @@@ out
  }
  
  static void
 -gst_subtitle_overlay_init (GstSubtitleOverlay * self,
 -    GstSubtitleOverlayClass * klass)
 +gst_subtitle_overlay_init (GstSubtitleOverlay * self)
  {
    GstPadTemplate *templ;
    GstPad *proxypad = NULL;
        gst_ghost_pad_new_no_target_from_template ("video_sink", templ);
    gst_pad_set_event_function (self->video_sinkpad,
        GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_event));
 -  gst_pad_set_setcaps_function (self->video_sinkpad,
 -      GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_setcaps));
    gst_pad_set_chain_function (self->video_sinkpad,
        GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_chain));
  
        GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
            (self->video_sinkpad)));
    self->video_block_pad = proxypad;
 +
    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_unlink));
    gst_pad_set_event_function (self->subtitle_sinkpad,
        GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_event));
 -  gst_pad_set_setcaps_function (self->subtitle_sinkpad,
 -      GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_setcaps));
    gst_pad_set_chain_function (self->subtitle_sinkpad,
        GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_chain));
    gst_pad_set_getcaps_function (self->subtitle_sinkpad,
        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 =
        GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
   * <refsect2>
   * <title>Example pipelines</title>
   * |[
 - * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videorate ! video/x-raw-yuv,framerate=15/1 ! xvimagesink
 + * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videorate ! video/x-raw,framerate=15/1 ! xvimagesink
   * ]| Decode an Ogg/Theora file and adjust the framerate to 15 fps before playing.
   * To create the test Ogg/Theora file refer to the documentation of theoraenc.
   * |[
 - * gst-launch -v v4lsrc ! videorate ! video/x-raw-yuv,framerate=25/2 ! theoraenc ! oggmux ! filesink location=v4l.ogg
 + * gst-launch -v v4l2src ! videorate ! video/x-raw,framerate=25/2 ! theoraenc ! oggmux ! filesink location=recording.ogg
   * ]| Capture video from a V4L device, and adjust the stream to 12.5 fps before
   * encoding to Ogg/Theora.
   * </refsect2>
@@@ -108,49 -108,91 +108,68 @@@ static GstStaticPadTemplate gst_video_r
      GST_STATIC_PAD_TEMPLATE ("src",
      GST_PAD_SRC,
      GST_PAD_ALWAYS,
 -    GST_STATIC_CAPS ("video/x-raw-yuv;"
 -        "video/x-raw-rgb;" "video/x-raw-gray;" "image/jpeg;" "image/png")
 +    GST_STATIC_CAPS ("video/x-raw;" "image/jpeg;" "image/png")
      );
  
  static GstStaticPadTemplate gst_video_rate_sink_template =
      GST_STATIC_PAD_TEMPLATE ("sink",
      GST_PAD_SINK,
      GST_PAD_ALWAYS,
 -    GST_STATIC_CAPS ("video/x-raw-yuv;"
 -        "video/x-raw-rgb;" "video/x-raw-gray;" "image/jpeg;" "image/png")
 +    GST_STATIC_CAPS ("video/x-raw;" "image/jpeg;" "image/png")
      );
  
  static void gst_video_rate_swap_prev (GstVideoRate * videorate,
      GstBuffer * buffer, gint64 time);
- static gboolean gst_video_rate_event (GstPad * pad, GstEvent * event);
- static gboolean gst_video_rate_query (GstPad * pad, GstQuery * query);
- static GstFlowReturn gst_video_rate_chain (GstPad * pad, GstBuffer * buffer);
 -static gboolean gst_video_rate_event (GstBaseTransform * trans,
++static gboolean gst_video_rate_sink_event (GstBaseTransform * trans,
+     GstEvent * event);
+ static gboolean gst_video_rate_query (GstBaseTransform * trans,
+     GstPadDirection direction, GstQuery * query);
+ static gboolean gst_video_rate_setcaps (GstBaseTransform * trans,
+     GstCaps * in_caps, GstCaps * out_caps);
+ static GstCaps *gst_video_rate_transform_caps (GstBaseTransform * trans,
 -    GstPadDirection direction, GstCaps * caps);
++    GstPadDirection direction, GstCaps * caps, GstCaps * filter);
+ static void gst_video_rate_fixate_caps (GstBaseTransform * trans,
+     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
 -static GstFlowReturn gst_video_rate_prepare_output_buffer (GstBaseTransform *
 -    trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
+ static GstFlowReturn gst_video_rate_transform_ip (GstBaseTransform * trans,
+     GstBuffer * buf);
+ static gboolean gst_video_rate_start (GstBaseTransform * trans);
  
  static void gst_video_rate_set_property (GObject * object,
      guint prop_id, const GValue * value, GParamSpec * pspec);
  static void gst_video_rate_get_property (GObject * object,
      guint prop_id, GValue * value, GParamSpec * pspec);
  
- static GstStateChangeReturn gst_video_rate_change_state (GstElement * element,
-     GstStateChange transition);
- /*static guint gst_video_rate_signals[LAST_SIGNAL] = { 0 }; */
  static GParamSpec *pspec_drop = NULL;
  static GParamSpec *pspec_duplicate = NULL;
  
 -GST_BOILERPLATE (GstVideoRate, gst_video_rate,
 -    GstBaseTransform, GST_TYPE_BASE_TRANSFORM);
 -
 -static void
 -gst_video_rate_base_init (gpointer g_class)
 -{
 -  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 -
 -  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));
 -}
 +#define gst_video_rate_parent_class parent_class
- G_DEFINE_TYPE (GstVideoRate, gst_video_rate, GST_TYPE_ELEMENT);
++G_DEFINE_TYPE (GstVideoRate, gst_video_rate, GST_TYPE_BASE_TRANSFORM);
  
  static void
  gst_video_rate_class_init (GstVideoRateClass * klass)
  {
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
-   parent_class = g_type_class_peek_parent (klass);
 +  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+   GstBaseTransformClass *base_class = GST_BASE_TRANSFORM_CLASS (klass);
  
 -  parent_class = g_type_class_peek_parent (klass);
 -
    object_class->set_property = gst_video_rate_set_property;
    object_class->get_property = gst_video_rate_get_property;
  
 -  base_class->prepare_output_buffer =
 -      GST_DEBUG_FUNCPTR (gst_video_rate_prepare_output_buffer);
 -  base_class->event = GST_DEBUG_FUNCPTR (gst_video_rate_event);
+   base_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_rate_setcaps);
+   base_class->transform_caps =
+       GST_DEBUG_FUNCPTR (gst_video_rate_transform_caps);
+   base_class->transform_ip = GST_DEBUG_FUNCPTR (gst_video_rate_transform_ip);
++  base_class->sink_event = GST_DEBUG_FUNCPTR (gst_video_rate_sink_event);
+   base_class->start = GST_DEBUG_FUNCPTR (gst_video_rate_start);
+   base_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_video_rate_fixate_caps);
+   base_class->query = GST_DEBUG_FUNCPTR (gst_video_rate_query);
    g_object_class_install_property (object_class, ARG_IN,
        g_param_spec_uint64 ("in", "In",
            "Number of input frames", 0, G_MAXUINT64, 0,
            "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
+    * Since: 0.10.36
     */
    g_object_class_install_property (object_class, ARG_DROP_ONLY,
        g_param_spec_boolean ("drop-only", "Only Drop",
     * where the framerate is calculated using a moving average over the
     * configured.
     *
-    * Since: 0.10.34
+    * Since: 0.10.36
     */
    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);
- }
- /* return the caps that can be used on out_pad given in_caps on in_pad */
- static gboolean
- gst_video_rate_transformcaps (GstPad * in_pad, GstCaps * in_caps,
-     GstPad * out_pad, GstCaps ** out_caps, GstCaps * filter)
- {
-   GstCaps *intersect, *in_templ;
-   gint i;
-   GSList *extra_structures = NULL;
-   GSList *iter;
-   in_templ = gst_pad_get_pad_template_caps (in_pad);
-   intersect =
-       gst_caps_intersect_full (in_caps, in_templ, GST_CAPS_INTERSECT_FIRST);
-   gst_caps_unref (in_templ);
 +
-   /* all possible framerates are allowed */
-   for (i = 0; i < gst_caps_get_size (intersect); i++) {
-     GstStructure *structure;
++  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>");
 +
-     structure = gst_caps_get_structure (intersect, i);
++  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));
 +
+ }
  
-     if (gst_structure_has_field (structure, "framerate")) {
-       GstStructure *copy_structure;
+ static GstCaps *
+ gst_video_rate_transform_caps (GstBaseTransform * trans,
 -    GstPadDirection direction, GstCaps * caps)
++    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+ {
+   GstCaps *ret;
+   GstStructure *s;
  
-       copy_structure = gst_structure_copy (structure);
-       gst_structure_set (copy_structure,
-           "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
-       extra_structures = g_slist_append (extra_structures, copy_structure);
-     }
-   }
+   /* Should always be called with simple caps */
+   g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
  
-   /* append the extra structures */
-   for (iter = extra_structures; iter != NULL; iter = g_slist_next (iter)) {
-     gst_caps_append_structure (intersect, (GstStructure *) iter->data);
-   }
-   g_slist_free (extra_structures);
+   ret = gst_caps_copy (caps);
  
-   if (filter) {
-     GstCaps *tmp;
+   s = gst_structure_copy (gst_caps_get_structure (caps, 0));
  
-     tmp = gst_caps_intersect_full (filter, intersect, GST_CAPS_INTERSECT_FIRST);
-     gst_caps_unref (intersect);
-     intersect = tmp;
-   }
+   /* set the framerate as a range */
+   gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
+       G_MAXINT, 1, NULL);
  
-   *out_caps = intersect;
+   gst_caps_append_structure (ret, s);
  
-   return TRUE;
+   return ret;
  }
  
- static GstCaps *
- gst_video_rate_getcaps (GstPad * pad, GstCaps * filter)
+ static void
+ gst_video_rate_fixate_caps (GstBaseTransform * trans,
+     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
  {
-   GstVideoRate *videorate;
-   GstPad *otherpad;
-   GstCaps *caps;
-   videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
-   otherpad = (pad == videorate->srcpad) ? videorate->sinkpad :
-       videorate->srcpad;
-   /* we can do what the peer can */
-   caps = gst_pad_peer_get_caps (otherpad, filter);
-   if (caps) {
-     GstCaps *transform, *intersect;
-     gst_video_rate_transformcaps (otherpad, caps, pad, &transform, filter);
+   GstStructure *s;
+   gint num, denom;
  
-     /* Now prefer the downstream caps if possible */
-     intersect =
-         gst_caps_intersect_full (caps, transform, GST_CAPS_INTERSECT_FIRST);
-     if (!gst_caps_is_empty (intersect)) {
-       gst_caps_append (intersect, transform);
-       gst_caps_unref (caps);
-       caps = intersect;
-     } else {
-       gst_caps_unref (intersect);
-       caps = transform;
-     }
-   } else {
-     /* no peer, our padtemplate is enough then */
-     caps = gst_pad_get_pad_template_caps (pad);
-     if (filter) {
-       GstCaps *intersection;
-       intersection =
-           gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
-       gst_caps_unref (caps);
-       caps = intersection;
-     }
-   }
+   s = gst_caps_get_structure (caps, 0);
+   if (G_UNLIKELY (!gst_structure_get_fraction (s, "framerate", &num, &denom)))
+     return;
  
-   return caps;
+   s = gst_caps_get_structure (othercaps, 0);
+   gst_structure_fixate_field_nearest_fraction (s, "framerate", num, denom);
  }
  
  static gboolean
- gst_video_rate_set_src_caps (GstVideoRate * videorate, GstCaps * caps)
+ gst_video_rate_setcaps (GstBaseTransform * trans, GstCaps * in_caps,
+     GstCaps * out_caps)
  {
 -  GstVideoRate *videorate;
++  GstVideoRate *videorate = GST_VIDEO_RATE (trans);
    GstStructure *structure;
+   gboolean ret = TRUE;
    gint rate_numerator, rate_denominator;
  
-   GST_DEBUG_OBJECT (videorate, "src caps %" GST_PTR_FORMAT, caps);
+   videorate = GST_VIDEO_RATE (trans);
+   GST_DEBUG_OBJECT (trans, "setcaps called in: %" GST_PTR_FORMAT
+       " out: %" GST_PTR_FORMAT, in_caps, out_caps);
+   structure = gst_caps_get_structure (in_caps, 0);
+   if (!gst_structure_get_fraction (structure, "framerate",
+           &rate_numerator, &rate_denominator))
+     goto no_framerate;
+   videorate->from_rate_numerator = rate_numerator;
+   videorate->from_rate_denominator = rate_denominator;
  
-   structure = gst_caps_get_structure (caps, 0);
+   structure = gst_caps_get_structure (out_caps, 0);
    if (!gst_structure_get_fraction (structure, "framerate",
            &rate_numerator, &rate_denominator))
      goto no_framerate;
    videorate->out_frame_count = 0;
    videorate->to_rate_numerator = rate_numerator;
    videorate->to_rate_denominator = rate_denominator;
-   videorate->wanted_diff = gst_util_uint64_scale_int (GST_SECOND,
-       rate_denominator, rate_numerator);
-   gst_pad_push_event (videorate->srcpad, gst_event_new_caps (caps));
-   return TRUE;
-   /* ERRORS */
- no_framerate:
-   {
-     GST_DEBUG_OBJECT (videorate, "no framerate specified");
-     return FALSE;
-   }
- }
  
- static gboolean
- gst_video_rate_set_sink_caps (GstVideoRate * videorate, GstCaps * caps)
- {
-   GstStructure *structure;
-   gboolean ret = TRUE;
-   gint rate_numerator, rate_denominator;
-   GST_DEBUG_OBJECT (videorate, "sink caps %" GST_PTR_FORMAT, caps);
-   structure = gst_caps_get_structure (caps, 0);
-   if (!gst_structure_get_fraction (structure, "framerate",
-           &rate_numerator, &rate_denominator))
-     goto no_framerate;
-   videorate->from_rate_numerator = rate_numerator;
-   videorate->from_rate_denominator = rate_denominator;
-   /* now try to find something for the peer */
-   if (gst_pad_peer_accept_caps (videorate->srcpad, caps)) {
-     /* the peer accepts the caps as they are */
-     ret = gst_video_rate_set_src_caps (videorate, caps);
-   } else {
-     GstCaps *transform = NULL;
-     ret = FALSE;
-     /* see how we can transform the input caps */
-     if (!gst_video_rate_transformcaps (videorate->sinkpad, caps,
-             videorate->srcpad, &transform, NULL))
-       goto no_transform;
-     GST_DEBUG_OBJECT (videorate, "transform %" GST_PTR_FORMAT, transform);
-     /* see what the peer can do */
-     caps = gst_pad_peer_get_caps (videorate->srcpad, transform);
-     GST_DEBUG_OBJECT (videorate, "icaps %" GST_PTR_FORMAT, caps);
-     /* could turn up empty, due to e.g. colorspace etc */
-     if (gst_caps_get_size (caps) == 0) {
-       gst_caps_unref (caps);
-       goto no_transform;
-     }
+   if (rate_numerator)
+     videorate->wanted_diff = gst_util_uint64_scale_int (GST_SECOND,
+         rate_denominator, rate_numerator);
+   else
+     videorate->wanted_diff = 0;
  
-     /* take first possibility */
-     caps = gst_caps_make_writable (caps);
-     gst_caps_truncate (caps);
-     structure = gst_caps_get_structure (caps, 0);
-     /* and fixate */
-     gst_structure_fixate_field_nearest_fraction (structure, "framerate",
-         rate_numerator, rate_denominator);
-     gst_structure_get_fraction (structure, "framerate",
-         &rate_numerator, &rate_denominator);
-     videorate->to_rate_numerator = rate_numerator;
-     videorate->to_rate_denominator = rate_denominator;
-     if (gst_structure_has_field (structure, "interlaced"))
-       gst_structure_fixate_field_boolean (structure, "interlaced", FALSE);
-     if (gst_structure_has_field (structure, "color-matrix"))
-       gst_structure_fixate_field_string (structure, "color-matrix", "sdtv");
-     if (gst_structure_has_field (structure, "chroma-site"))
-       gst_structure_fixate_field_string (structure, "chroma-site", "mpeg2");
-     if (gst_structure_has_field (structure, "pixel-aspect-ratio"))
-       gst_structure_fixate_field_nearest_fraction (structure,
-           "pixel-aspect-ratio", 1, 1);
-     ret = gst_video_rate_set_src_caps (videorate, caps);
-     gst_caps_unref (caps);
-   }
  done:
    /* After a setcaps, our caps may have changed. In that case, we can't use
     * the old buffer, if there was one (it might have different dimensions) */
    GST_DEBUG_OBJECT (videorate, "swapping old buffers");
    gst_video_rate_swap_prev (videorate, NULL, GST_CLOCK_TIME_NONE);
+   videorate->last_ts = GST_CLOCK_TIME_NONE;
+   videorate->average = 0;
  
    return ret;
  
  no_framerate:
    {
      GST_DEBUG_OBJECT (videorate, "no framerate specified");
-     goto done;
-   }
- no_transform:
-   {
-     GST_DEBUG_OBJECT (videorate, "no framerate transform possible");
      ret = FALSE;
      goto done;
    }
@@@ -474,36 -379,21 +367,21 @@@ gst_video_rate_reset (GstVideoRate * vi
  }
  
  static void
 -gst_video_rate_init (GstVideoRate * videorate, GstVideoRateClass * klass)
 +gst_video_rate_init (GstVideoRate * videorate)
  {
-   videorate->sinkpad =
-       gst_pad_new_from_static_template (&gst_video_rate_sink_template, "sink");
-   gst_pad_set_event_function (videorate->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_video_rate_event));
-   gst_pad_set_chain_function (videorate->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_video_rate_chain));
-   gst_pad_set_getcaps_function (videorate->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_video_rate_getcaps));
-   gst_element_add_pad (GST_ELEMENT (videorate), videorate->sinkpad);
-   videorate->srcpad =
-       gst_pad_new_from_static_template (&gst_video_rate_src_template, "src");
-   gst_pad_set_query_function (videorate->srcpad,
-       GST_DEBUG_FUNCPTR (gst_video_rate_query));
-   gst_pad_set_getcaps_function (videorate->srcpad,
-       GST_DEBUG_FUNCPTR (gst_video_rate_getcaps));
-   gst_element_add_pad (GST_ELEMENT (videorate), videorate->srcpad);
    gst_video_rate_reset (videorate);
    videorate->silent = DEFAULT_SILENT;
    videorate->new_pref = DEFAULT_NEW_PREF;
    videorate->drop_only = DEFAULT_DROP_ONLY;
    videorate->average_period = DEFAULT_AVERAGE_PERIOD;
+   videorate->average_period_set = DEFAULT_AVERAGE_PERIOD;
  
    videorate->from_rate_numerator = 0;
    videorate->from_rate_denominator = 0;
    videorate->to_rate_numerator = 0;
    videorate->to_rate_denominator = 0;
+   gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (videorate), TRUE);
  }
  
  /* flush the oldest buffer */
@@@ -518,7 -408,8 +396,7 @@@ gst_video_rate_flush_prev (GstVideoRat
      goto eos_before_buffers;
  
    /* make sure we can write to the metadata */
 -  outbuf = gst_buffer_make_metadata_writable
 -      (gst_buffer_ref (videorate->prevbuf));
 +  outbuf = gst_buffer_make_writable (gst_buffer_ref (videorate->prevbuf));
  
    GST_BUFFER_OFFSET (outbuf) = videorate->out;
    GST_BUFFER_OFFSET_END (outbuf) = videorate->out + 1;
    if (videorate->to_rate_numerator) {
      /* interpolate next expected timestamp in the segment */
      videorate->next_ts =
 -        videorate->segment.accum + videorate->segment.start +
 +        videorate->segment.base + videorate->segment.start +
          videorate->base_ts + gst_util_uint64_scale (videorate->out_frame_count,
          videorate->to_rate_denominator * GST_SECOND,
          videorate->to_rate_numerator);
    /* 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_TIMESTAMP (outbuf) = push_ts - videorate->segment.base;
    }
  
    GST_LOG_OBJECT (videorate,
        "old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT,
        GST_TIME_ARGS (push_ts));
  
-   res = gst_pad_push (videorate->srcpad, outbuf);
+   res = gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (videorate), outbuf);
  
    return res;
  
@@@ -578,7 -469,7 +456,7 @@@ gst_video_rate_swap_prev (GstVideoRate 
    GST_LOG_OBJECT (videorate, "swap_prev: storing buffer %p in prev", buffer);
    if (videorate->prevbuf)
      gst_buffer_unref (videorate->prevbuf);
-   videorate->prevbuf = buffer;
+   videorate->prevbuf = buffer != NULL ? gst_buffer_ref (buffer) : NULL;
    videorate->prev_ts = time;
  }
  
@@@ -604,38 -495,30 +482,26 @@@ gst_video_rate_notify_duplicate (GstVid
  
  #define MAGIC_LIMIT  25
  static gboolean
- gst_video_rate_event (GstPad * pad, GstEvent * event)
 -gst_video_rate_event (GstBaseTransform * trans, GstEvent * event)
++gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
  {
    GstVideoRate *videorate;
-   gboolean ret;
  
-   videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
+   videorate = GST_VIDEO_RATE (trans);
  
    switch (GST_EVENT_TYPE (event)) {
-     case GST_EVENT_CAPS:
-     {
-       GstCaps *caps;
-       gst_event_parse_caps (event, &caps);
-       ret = gst_video_rate_set_sink_caps (videorate, caps);
-       gst_event_unref (event);
-       /* don't forward */
-       goto done;
-     }
 -    case GST_EVENT_NEWSEGMENT:
 +    case GST_EVENT_SEGMENT:
      {
 -      gint64 start, stop, time;
 -      gdouble rate, arate;
 -      gboolean update;
 -      GstFormat format;
 +      const GstSegment *segment;
  
 -      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
 -          &start, &stop, &time);
 +      gst_event_parse_segment (event, &segment);
  
 -      if (format != GST_FORMAT_TIME)
 +      if (segment->format != GST_FORMAT_TIME)
          goto format_error;
  
        GST_DEBUG_OBJECT (videorate, "handle NEWSEGMENT");
  
        /* close up the previous segment, if appropriate */
 -      if (!update && videorate->prevbuf) {
 +      if (videorate->prevbuf) {
          gint count = 0;
          GstFlowReturn res;
  
           * regardless, prevent going loopy in strange cases */
          while (res == GST_FLOW_OK && count <= MAGIC_LIMIT &&
              ((GST_CLOCK_TIME_IS_VALID (videorate->segment.stop) &&
 -                    videorate->next_ts - videorate->segment.accum
 +                    videorate->next_ts - videorate->segment.base
                      < videorate->segment.stop)
                  || count < 1)) {
            res = gst_video_rate_flush_prev (videorate, count > 0);
        }
  
        /* We just want to update the accumulated stream_time  */
 -      gst_segment_set_newsegment_full (&videorate->segment, update, rate, arate,
 -          format, start, stop, time);
 +      gst_segment_copy_into (segment, &videorate->segment);
  
        GST_DEBUG_OBJECT (videorate, "updated segment: %" GST_SEGMENT_FORMAT,
            &videorate->segment);
           * or only send out the stored buffer if there is no specific stop.
           * regardless, prevent going loopy in strange cases */
          while (res == GST_FLOW_OK && count <= MAGIC_LIMIT &&
 -            ((videorate->next_ts - videorate->segment.accum <
 +            ((videorate->next_ts - videorate->segment.base <
                      videorate->segment.stop)
                  || count < 1)) {
            res = gst_video_rate_flush_prev (videorate, count > 0);
                videorate->next_ts + GST_BUFFER_DURATION (videorate->prevbuf);
  
            while (res == GST_FLOW_OK && count <= MAGIC_LIMIT &&
 -              ((videorate->next_ts - videorate->segment.accum < end_ts)
 +              ((videorate->next_ts - videorate->segment.base < end_ts)
                    || count < 1)) {
              res = gst_video_rate_flush_prev (videorate, count > 0);
              count++;
        break;
    }
  
-   ret = gst_pad_push_event (videorate->srcpad, event);
- done:
-   gst_object_unref (videorate);
-   return ret;
+   return TRUE;
  
    /* ERRORS */
  format_error:
      GST_WARNING_OBJECT (videorate,
          "Got segment but doesn't have GST_FORMAT_TIME value");
      gst_event_unref (event);
-     ret = FALSE;
-     goto done;
+     return FALSE;
    }
  }
  
  static gboolean
- gst_video_rate_query (GstPad * pad, GstQuery * query)
+ gst_video_rate_query (GstBaseTransform * trans, GstPadDirection direction,
+     GstQuery * query)
  {
-   GstVideoRate *videorate;
+   GstVideoRate *videorate = GST_VIDEO_RATE (trans);
    gboolean res = FALSE;
+   GstPad *otherpad;
  
-   videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
+   otherpad = (direction == GST_PAD_SRC) ?
+       GST_BASE_TRANSFORM_SINK_PAD (trans) : GST_BASE_TRANSFORM_SRC_PAD (trans);
  
    switch (GST_QUERY_TYPE (query)) {
      case GST_QUERY_LATENCY:
        GstClockTime min, max;
        gboolean live;
        guint64 latency;
+       guint64 avg_period;
        GstPad *peer;
  
-       if ((peer = gst_pad_get_peer (videorate->sinkpad))) {
+       GST_OBJECT_LOCK (videorate);
+       avg_period = videorate->average_period_set;
+       GST_OBJECT_UNLOCK (videorate);
+       if (avg_period == 0 && (peer = gst_pad_get_peer (otherpad))) {
          if ((res = gst_pad_query (peer, query))) {
            gst_query_parse_latency (query, &live, &min, &max);
  
            gst_query_set_latency (query, live, min, max);
          }
          gst_object_unref (peer);
+         break;
        }
-       break;
+       /* Simple fallthrough if we don't have a latency or not a peer that we
+        * can't ask about its latency yet.. */
      }
      default:
-       res = gst_pad_query_default (pad, query);
 -      res = parent_class->query (trans, direction, query);
++      res =
++          GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
++          query);
        break;
    }
-   gst_object_unref (videorate);
  
    return res;
  }
  
  static GstFlowReturn
- gst_video_rate_chain_max_avg (GstVideoRate * videorate, GstBuffer * buf)
+ gst_video_rate_trans_ip_max_avg (GstVideoRate * videorate, GstBuffer * buf)
  {
    GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
  
  
  push:
    videorate->out++;
-   return gst_pad_push (videorate->srcpad, buf);
+   return GST_FLOW_OK;
  
  drop:
-   gst_buffer_unref (buf);
    if (!videorate->silent)
      gst_video_rate_notify_drop (videorate);
-   return GST_FLOW_OK;
+   return GST_BASE_TRANSFORM_FLOW_DROPPED;
  }
  
  static GstFlowReturn
- gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
 -gst_video_rate_prepare_output_buffer (GstBaseTransform * trans,
 -    GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf)
 -{
 -  if (gst_buffer_is_metadata_writable (input)) {
 -    gst_buffer_set_caps (input, caps);
 -    *buf = gst_buffer_ref (input);
 -  } else {
 -    *buf = gst_buffer_create_sub (input, 0, GST_BUFFER_SIZE (input));
 -    gst_buffer_set_caps (*buf, caps);
 -  }
 -
 -  return GST_FLOW_OK;
 -}
 -
 -static GstFlowReturn
+ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
  {
    GstVideoRate *videorate;
-   GstFlowReturn res = GST_FLOW_OK;
+   GstFlowReturn res = GST_BASE_TRANSFORM_FLOW_DROPPED;
    GstClockTime intime, in_ts, in_dur;
    GstClockTime avg_period;
    gboolean skip = FALSE;
  
-   videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
+   videorate = GST_VIDEO_RATE (trans);
  
    /* make sure the denominators are not 0 */
    if (videorate->from_rate_denominator == 0 ||
  
    /* MT-safe switching between modes */
    if (G_UNLIKELY (avg_period != videorate->average_period)) {
+     gboolean switch_mode = (avg_period == 0 || videorate->average_period == 0);
      videorate->average_period = avg_period;
      videorate->last_ts = GST_CLOCK_TIME_NONE;
-     if (avg_period && !videorate->average) {
-       /* enabling average mode */
-       videorate->average = 0;
-     } else {
-       /* enable regular mode */
-       gst_video_rate_swap_prev (videorate, NULL, 0);
-       /* arrange for skip-to-first behaviour */
-       videorate->next_ts = GST_CLOCK_TIME_NONE;
-       skip = TRUE;
+     if (switch_mode) {
+       if (avg_period) {
+         /* enabling average mode */
+         videorate->average = 0;
+         /* make sure no cached buffers from regular mode are left */
+         gst_video_rate_swap_prev (videorate, NULL, 0);
+       } else {
+         /* enable regular mode */
+         videorate->next_ts = GST_CLOCK_TIME_NONE;
+         skip = TRUE;
+       }
+       /* max averaging mode has a no latency, normal mode does */
+       gst_element_post_message (GST_ELEMENT (videorate),
+           gst_message_new_latency (GST_OBJECT (videorate)));
      }
    }
  
    if (videorate->average_period > 0)
-     return gst_video_rate_chain_max_avg (videorate, buffer);
+     return gst_video_rate_trans_ip_max_avg (videorate, buffer);
  
    in_ts = GST_BUFFER_TIMESTAMP (buffer);
    in_dur = GST_BUFFER_DURATION (buffer);
  
    /* the input time is the time in the segment + all previously accumulated
     * segments */
 -  intime = in_ts + videorate->segment.accum;
 +  intime = in_ts + videorate->segment.base;
  
    /* we need to have two buffers to compare */
    if (videorate->prevbuf == NULL) {
          videorate->base_ts = in_ts - videorate->segment.start;
          videorate->out_frame_count = 0;
        } else {
 -        videorate->next_ts =
 -            videorate->segment.start + videorate->segment.accum;
 +        videorate->next_ts = videorate->segment.start + videorate->segment.base;
        }
      }
    } else {
        videorate->drop++;
        if (!videorate->silent)
          gst_video_rate_notify_drop (videorate);
-       gst_buffer_unref (buffer);
        goto done;
      }
  
  
        /* output first one when its the best */
        if (diff1 <= diff2) {
+         GstFlowReturn r;
          count++;
  
          /* on error the _flush function posted a warning already */
-         if ((res =
-                 gst_video_rate_flush_prev (videorate,
+         if ((r = gst_video_rate_flush_prev (videorate,
                      count > 1)) != GST_FLOW_OK) {
-           gst_buffer_unref (buffer);
+           res = r;
            goto done;
          }
        }
@@@ -1045,7 -953,6 +921,6 @@@ done
  not_negotiated:
    {
      GST_WARNING_OBJECT (videorate, "no framerate negotiated");
-     gst_buffer_unref (buffer);
      res = GST_FLOW_NOT_NEGOTIATED;
      goto done;
    }
@@@ -1054,11 -961,18 +929,18 @@@ invalid_buffer
    {
      GST_WARNING_OBJECT (videorate,
          "Got buffer with GST_CLOCK_TIME_NONE timestamp, discarding it");
-     gst_buffer_unref (buffer);
+     res = GST_BASE_TRANSFORM_FLOW_DROPPED;
      goto done;
    }
  }
  
+ static gboolean
+ gst_video_rate_start (GstBaseTransform * trans)
+ {
+   gst_video_rate_reset (GST_VIDEO_RATE (trans));
+   return TRUE;
+ }
  static void
  gst_video_rate_set_property (GObject * object,
      guint prop_id, const GValue * value, GParamSpec * pspec)
        videorate->drop_only = g_value_get_boolean (value);
        break;
      case ARG_AVERAGE_PERIOD:
-       videorate->average_period = g_value_get_uint64 (value);
+       videorate->average_period_set = g_value_get_uint64 (value);
        break;
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@@ -1122,7 -1036,7 +1004,7 @@@ gst_video_rate_get_property (GObject * 
        g_value_set_boolean (value, videorate->drop_only);
        break;
      case ARG_AVERAGE_PERIOD:
-       g_value_set_uint64 (value, videorate->average_period);
+       g_value_set_uint64 (value, videorate->average_period_set);
        break;
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    GST_OBJECT_UNLOCK (videorate);
  }
  
- static GstStateChangeReturn
- gst_video_rate_change_state (GstElement * element, GstStateChange transition)
- {
-   GstStateChangeReturn ret;
-   GstVideoRate *videorate;
-   videorate = GST_VIDEO_RATE (element);
-   switch (transition) {
-     case GST_STATE_CHANGE_READY_TO_PAUSED:
-       videorate->discont = TRUE;
-       videorate->last_ts = -1;
-       break;
-     default:
-       break;
-   }
-   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-   switch (transition) {
-     case GST_STATE_CHANGE_PAUSED_TO_READY:
-       gst_video_rate_reset (videorate);
-       break;
-     default:
-       break;
-   }
-   return ret;
- }
  static gboolean
  plugin_init (GstPlugin * plugin)
  {
index 0000000,0000000..baca0d5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,48 @@@
++diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c
++index 8d22186..7afcfdd 100644
++--- a/gst/videorate/gstvideorate.c
+++++ b/gst/videorate/gstvideorate.c
++@@ -357,6 +357,7 @@ gst_video_rate_reset (GstVideoRate * videorate)
++   videorate->drop = 0;
++   videorate->dup = 0;
++   videorate->next_ts = GST_CLOCK_TIME_NONE;
+++  videorate->discont = TRUE;
++   gst_video_rate_swap_prev (videorate, NULL, 0);
++ 
++   gst_segment_init (&videorate->segment, GST_FORMAT_TIME);
++@@ -409,6 +410,13 @@ gst_video_rate_flush_prev (GstVideoRate * videorate)
++   GST_BUFFER_OFFSET (outbuf) = videorate->out;
++   GST_BUFFER_OFFSET_END (outbuf) = videorate->out + 1;
++ 
+++  if (videorate->discont) {
+++    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+++    videorate->discont = FALSE;
+++  }
+++  else
+++    GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DISCONT);
+++
++   /* this is the timestamp we put on the buffer */
++   push_ts = videorate->next_ts;
++ 
++@@ -810,6 +818,9 @@ gst_video_rate_change_state (GstElement * element, GstStateChange transition)
++   videorate = GST_VIDEO_RATE (element);
++ 
++   switch (transition) {
+++    case GST_STATE_CHANGE_READY_TO_PAUSED:
+++      videorate->discont = TRUE;
+++      break;
++     default:
++       break;
++   }
++diff --git a/gst/videorate/gstvideorate.h b/gst/videorate/gstvideorate.h
++index ea6063b..fe7feb6 100644
++--- a/gst/videorate/gstvideorate.h
+++++ b/gst/videorate/gstvideorate.h
++@@ -56,6 +56,7 @@ struct _GstVideoRate
++   GstBuffer *prevbuf;
++   guint64 prev_ts;              /* Previous buffer timestamp */
++   guint64 segment_out;          /* in-segment counting */
+++  gboolean discont;
++ 
++   /* segment handling */
++   GstSegment segment;
@@@ -20,7 -20,7 +20,7 @@@
  
  /**
   * SECTION:element-videoscale
 - * @see_also: videorate, ffmpegcolorspace
 + * @see_also: videorate, videoconvert
   *
   * This element resizes video frames. By default the element will try to
   * negotiate to the same size on the source and sinkpad so that no scaling
   * <refsect2>
   * <title>Example pipelines</title>
   * |[
 - * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! ffmpegcolorspace ! videoscale ! ximagesink
 + * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videoconvert ! videoscale ! ximagesink
   * ]| Decode an Ogg/Theora and display the video using ximagesink. Since
   * ximagesink cannot perform scaling, the video scaling will be performed by
   * videoscale when you resize the video window.
   * To create the test Ogg/Theora file refer to the documentation of theoraenc.
   * |[
 - * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videoscale ! video/x-raw-yuv, width=50 ! xvimagesink
 + * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videoscale ! video/x-raw, width=50 ! xvimagesink
   * ]| Decode an Ogg/Theora and display the video using xvimagesink with a width
   * of 50.
   * </refsect2>
@@@ -76,8 -76,7 +76,8 @@@
  
  #include <math.h>
  
 -#include <gst/video/video.h>
 +#include <gst/video/gstmetavideo.h>
 +#include <gst/video/gstvideopool.h>
  
  #include "gstvideoscale.h"
  #include "gstvideoscaleorc.h"
@@@ -90,26 -89,58 +90,35 @@@ GST_DEBUG_CATEGORY (video_scale_debug)
  
  #define DEFAULT_PROP_METHOD       GST_VIDEO_SCALE_BILINEAR
  #define DEFAULT_PROP_ADD_BORDERS  FALSE
+ #define DEFAULT_PROP_SHARPNESS    1.0
+ #define DEFAULT_PROP_SHARPEN      0.0
+ #define DEFAULT_PROP_DITHER       FALSE
+ #define DEFAULT_PROP_SUBMETHOD    1
+ #define DEFAULT_PROP_ENVELOPE     2.0
  
  enum
  {
    PROP_0,
    PROP_METHOD,
-   PROP_ADD_BORDERS
-       /* FILL ME */
+   PROP_ADD_BORDERS,
+   PROP_SHARPNESS,
+   PROP_SHARPEN,
+   PROP_DITHER,
+   PROP_SUBMETHOD,
+   PROP_ENVELOPE
  };
  
  #undef GST_VIDEO_SIZE_RANGE
  #define GST_VIDEO_SIZE_RANGE "(int) [ 1, 32767]"
  
 +#define GST_VIDEO_FORMATS "{ \"I420\", \"YV12\", \"YUY2\", \"UYVY\", \"AYUV\", \"RGBx\", " \
 +    "\"BGRx\", \"xRGB\", \"xBGR\", \"RGBA\", \"BGRA\", \"ARGB\", \"ABGR\", \"RGB\", " \
 +    "\"BGR\", \"Y41B\", \"Y42B\", \"YVYU\", \"Y444\", \"GRAY8\", \"GRAY16_BE\", \"GRAY16_LE\", " \
 +    "\"v308\", \"Y800\", \"Y16\", \"RGB16\", \"RGB15\", \"ARGB64\", \"AYUV64\" } "
 +
 +
  static GstStaticCaps gst_video_scale_format_caps[] = {
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_ARGB),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRA),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_ABGR),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_xBGR),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y444")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("v308")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_BGR),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y42B")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YVYU")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("UYVY")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YV12")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y41B")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB_16),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB_15),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_GRAY16 ("BYTE_ORDER")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y16 ")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_GRAY8),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y800")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y8  ")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("GREY")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AY64")),
 -  GST_STATIC_CAPS (GST_VIDEO_CAPS_ARGB_64)
 +  GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS))
  };
  
  #define GST_TYPE_VIDEO_SCALE_METHOD (gst_video_scale_method_get_type())
@@@ -122,6 -153,7 +131,7 @@@ gst_video_scale_method_get_type (void
      {GST_VIDEO_SCALE_NEAREST, "Nearest Neighbour", "nearest-neighbour"},
      {GST_VIDEO_SCALE_BILINEAR, "Bilinear", "bilinear"},
      {GST_VIDEO_SCALE_4TAP, "4-tap", "4-tap"},
+     {GST_VIDEO_SCALE_LANCZOS, "Lanczos", "lanczos"},
      {0, NULL, NULL},
    };
  
@@@ -158,14 -190,14 +168,14 @@@ static GstPadTemplate 
  gst_video_scale_src_template_factory (void)
  {
    return gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
 -      gst_caps_ref (gst_video_scale_get_capslist ()));
 +      gst_video_scale_get_capslist ());
  }
  
  static GstPadTemplate *
  gst_video_scale_sink_template_factory (void)
  {
    return gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
 -      gst_caps_ref (gst_video_scale_get_capslist ()));
 +      gst_video_scale_get_capslist ());
  }
  
  
@@@ -175,13 -207,11 +185,13 @@@ static gboolean gst_video_scale_src_eve
  
  /* base transform vmethods */
  static GstCaps *gst_video_scale_transform_caps (GstBaseTransform * trans,
 -    GstPadDirection direction, GstCaps * caps);
 +    GstPadDirection direction, GstCaps * caps, GstCaps * filter);
  static gboolean gst_video_scale_set_caps (GstBaseTransform * trans,
      GstCaps * in, GstCaps * out);
  static gboolean gst_video_scale_get_unit_size (GstBaseTransform * trans,
 -    GstCaps * caps, guint * size);
 +    GstCaps * caps, gsize * size);
 +static gboolean gst_video_scale_decide_allocation (GstBaseTransform * trans,
 +    GstQuery * query);
  static GstFlowReturn gst_video_scale_transform (GstBaseTransform * trans,
      GstBuffer * in, GstBuffer * out);
  static void gst_video_scale_fixate_caps (GstBaseTransform * base,
@@@ -192,14 -222,28 +202,14 @@@ static void gst_video_scale_set_propert
  static void gst_video_scale_get_property (GObject * object, guint prop_id,
      GValue * value, GParamSpec * pspec);
  
 -GST_BOILERPLATE (GstVideoScale, gst_video_scale, GstVideoFilter,
 -    GST_TYPE_VIDEO_FILTER);
 -
 -static void
 -gst_video_scale_base_init (gpointer g_class)
 -{
 -  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 -
 -  gst_element_class_set_details_simple (element_class,
 -      "Video scaler", "Filter/Converter/Video/Scaler",
 -      "Resizes video", "Wim Taymans <wim.taymans@chello.be>");
 -
 -  gst_element_class_add_pad_template (element_class,
 -      gst_video_scale_sink_template_factory ());
 -  gst_element_class_add_pad_template (element_class,
 -      gst_video_scale_src_template_factory ());
 -}
 +#define gst_video_scale_parent_class parent_class
 +G_DEFINE_TYPE (GstVideoScale, gst_video_scale, GST_TYPE_VIDEO_FILTER);
  
  static void
  gst_video_scale_class_init (GstVideoScaleClass * klass)
  {
    GObjectClass *gobject_class = (GObjectClass *) klass;
 +  GstElementClass *element_class = (GstElementClass *) klass;
    GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
  
    gobject_class->finalize = (GObjectFinalizeFunc) gst_video_scale_finalize;
            DEFAULT_PROP_ADD_BORDERS,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
+   g_object_class_install_property (gobject_class, PROP_SHARPNESS,
+       g_param_spec_double ("sharpness", "Sharpness",
+           "Sharpness of filter", 0.0, 2.0, DEFAULT_PROP_SHARPNESS,
+           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+   g_object_class_install_property (gobject_class, PROP_SHARPEN,
+       g_param_spec_double ("sharpen", "Sharpen",
+           "Sharpening", 0.0, 1.0, DEFAULT_PROP_SHARPEN,
+           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+   g_object_class_install_property (gobject_class, PROP_DITHER,
+       g_param_spec_boolean ("dither", "Dither",
+           "Add dither (only used for Lanczos method)",
+           DEFAULT_PROP_DITHER,
+           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ #if 0
+   /* I am hiding submethod for now, since it's poorly named, poorly
+    * documented, and will probably just get people into trouble. */
+   g_object_class_install_property (gobject_class, PROP_SUBMETHOD,
+       g_param_spec_int ("submethod", "submethod",
+           "submethod", 0, 3, DEFAULT_PROP_SUBMETHOD,
+           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ #endif
+   g_object_class_install_property (gobject_class, PROP_ENVELOPE,
+       g_param_spec_double ("envelope", "Envelope",
+           "Size of filter envelope", 0.0, 5.0, DEFAULT_PROP_ENVELOPE,
+           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 +  gst_element_class_set_details_simple (element_class,
 +      "Video scaler", "Filter/Converter/Video/Scaler",
 +      "Resizes video", "Wim Taymans <wim.taymans@chello.be>");
 +
 +  gst_element_class_add_pad_template (element_class,
 +      gst_video_scale_sink_template_factory ());
 +  gst_element_class_add_pad_template (element_class,
 +      gst_video_scale_src_template_factory ());
 +
    trans_class->transform_caps =
        GST_DEBUG_FUNCPTR (gst_video_scale_transform_caps);
    trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_scale_set_caps);
    trans_class->get_unit_size =
        GST_DEBUG_FUNCPTR (gst_video_scale_get_unit_size);
 +  trans_class->decide_allocation =
 +      GST_DEBUG_FUNCPTR (gst_video_scale_decide_allocation);
    trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_scale_transform);
    trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_video_scale_fixate_caps);
    trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_scale_src_event);
  }
  
  static void
 -gst_video_scale_init (GstVideoScale * videoscale, GstVideoScaleClass * klass)
 +gst_video_scale_init (GstVideoScale * videoscale)
  {
    videoscale->tmp_buf = NULL;
    videoscale->method = DEFAULT_PROP_METHOD;
    videoscale->add_borders = DEFAULT_PROP_ADD_BORDERS;
+   videoscale->submethod = DEFAULT_PROP_SUBMETHOD;
+   videoscale->sharpness = DEFAULT_PROP_SHARPNESS;
+   videoscale->sharpen = DEFAULT_PROP_SHARPEN;
+   videoscale->dither = DEFAULT_PROP_DITHER;
+   videoscale->envelope = DEFAULT_PROP_ENVELOPE;
  }
  
  static void
@@@ -273,6 -341,31 +318,31 @@@ gst_video_scale_set_property (GObject 
        GST_OBJECT_UNLOCK (vscale);
        gst_base_transform_reconfigure (GST_BASE_TRANSFORM_CAST (vscale));
        break;
+     case PROP_SHARPNESS:
+       GST_OBJECT_LOCK (vscale);
+       vscale->sharpness = g_value_get_double (value);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
+     case PROP_SHARPEN:
+       GST_OBJECT_LOCK (vscale);
+       vscale->sharpen = g_value_get_double (value);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
+     case PROP_DITHER:
+       GST_OBJECT_LOCK (vscale);
+       vscale->dither = g_value_get_boolean (value);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
+     case PROP_SUBMETHOD:
+       GST_OBJECT_LOCK (vscale);
+       vscale->submethod = g_value_get_int (value);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
+     case PROP_ENVELOPE:
+       GST_OBJECT_LOCK (vscale);
+       vscale->envelope = g_value_get_double (value);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
@@@ -296,6 -389,31 +366,31 @@@ gst_video_scale_get_property (GObject 
        g_value_set_boolean (value, vscale->add_borders);
        GST_OBJECT_UNLOCK (vscale);
        break;
+     case PROP_SHARPNESS:
+       GST_OBJECT_LOCK (vscale);
+       g_value_set_double (value, vscale->sharpness);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
+     case PROP_SHARPEN:
+       GST_OBJECT_LOCK (vscale);
+       g_value_set_double (value, vscale->sharpen);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
+     case PROP_DITHER:
+       GST_OBJECT_LOCK (vscale);
+       g_value_set_boolean (value, vscale->dither);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
+     case PROP_SUBMETHOD:
+       GST_OBJECT_LOCK (vscale);
+       g_value_set_int (value, vscale->submethod);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
+     case PROP_ENVELOPE:
+       GST_OBJECT_LOCK (vscale);
+       g_value_set_double (value, vscale->envelope);
+       GST_OBJECT_UNLOCK (vscale);
+       break;
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
  
  static GstCaps *
  gst_video_scale_transform_caps (GstBaseTransform * trans,
 -    GstPadDirection direction, GstCaps * caps)
 +    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
  {
    GstCaps *ret;
    GstStructure *structure;
 -
 -  /* this function is always called with a simple caps */
 -  g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
 +  gint i, n;
  
    GST_DEBUG_OBJECT (trans,
        "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
        (direction == GST_PAD_SINK) ? "sink" : "src");
  
 -  ret = gst_caps_copy (caps);
 -  structure = gst_structure_copy (gst_caps_get_structure (ret, 0));
 +  ret = gst_caps_new_empty ();
 +  n = gst_caps_get_size (caps);
 +  for (i = 0; i < n; i++) {
 +    structure = gst_caps_get_structure (caps, i);
 +
 +    /* If this is already expressed by the existing caps
 +     * skip this structure */
 +    if (i > 0 && gst_caps_is_subset_structure (ret, structure))
 +      continue;
 +
 +    structure = gst_structure_copy (structure);
 +    gst_structure_set (structure,
 +        "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
 +        "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
 +
 +    /* if pixel aspect ratio, make a range of it */
 +    if (gst_structure_has_field (structure, "pixel-aspect-ratio")) {
 +      gst_structure_set (structure, "pixel-aspect-ratio",
 +          GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, NULL);
 +    }
 +    gst_caps_append_structure (ret, structure);
 +  }
  
 -  gst_structure_set (structure,
 -      "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
 -      "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
 +  if (filter) {
 +    GstCaps *intersection;
  
 -  /* if pixel aspect ratio, make a range of it */
 -  if (gst_structure_has_field (structure, "pixel-aspect-ratio")) {
 -    gst_structure_set (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE,
 -        1, G_MAXINT, G_MAXINT, 1, NULL);
 +    intersection =
 +        gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
 +    gst_caps_unref (ret);
 +    ret = intersection;
    }
 -  gst_caps_append_structure (ret, structure);
  
    GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
  
    return ret;
  }
  
 +
 +static gboolean
 +gst_video_scale_decide_allocation (GstBaseTransform * trans, GstQuery * query)
 +{
 +  GstBufferPool *pool = NULL;
 +  guint size, min, max, prefix, alignment;
 +
 +  gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
 +      &alignment, &pool);
 +
 +  if (pool) {
 +    GstStructure *config;
 +
 +    config = gst_buffer_pool_get_config (pool);
 +    gst_buffer_pool_config_add_option (config,
 +        GST_BUFFER_POOL_OPTION_META_VIDEO);
 +    gst_buffer_pool_set_config (pool, config);
 +  }
 +  return TRUE;
 +}
 +
  static gboolean
  gst_video_scale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
  {
    GstVideoScale *videoscale = GST_VIDEO_SCALE (trans);
    gboolean ret;
 +  GstVideoInfo in_info, out_info;
    gint from_dar_n, from_dar_d, to_dar_n, to_dar_d;
 -  gint from_par_n, from_par_d, to_par_n, to_par_d;
 -
 -  ret =
 -      gst_video_format_parse_caps (in, &videoscale->format,
 -      &videoscale->from_width, &videoscale->from_height);
 -  ret &=
 -      gst_video_format_parse_caps (out, NULL, &videoscale->to_width,
 -      &videoscale->to_height);
 -  if (!ret)
 -    goto done;
  
 -  videoscale->src_size = gst_video_format_get_size (videoscale->format,
 -      videoscale->from_width, videoscale->from_height);
 -  videoscale->dest_size = gst_video_format_get_size (videoscale->format,
 -      videoscale->to_width, videoscale->to_height);
 -
 -  if (!gst_video_parse_caps_pixel_aspect_ratio (in, &from_par_n, &from_par_d))
 -    from_par_n = from_par_d = 1;
 -  if (!gst_video_parse_caps_pixel_aspect_ratio (out, &to_par_n, &to_par_d))
 -    to_par_n = to_par_d = 1;
 +  ret = gst_video_info_from_caps (&in_info, in);
 +  ret &= gst_video_info_from_caps (&out_info, out);
 +  if (!ret)
 +    goto invalid_formats;
  
 -  if (!gst_util_fraction_multiply (videoscale->from_width,
 -          videoscale->from_height, from_par_n, from_par_d, &from_dar_n,
 +  if (!gst_util_fraction_multiply (in_info.width,
 +          in_info.height, out_info.par_n, out_info.par_d, &from_dar_n,
            &from_dar_d)) {
      from_dar_n = from_dar_d = -1;
    }
  
 -  if (!gst_util_fraction_multiply (videoscale->to_width,
 -          videoscale->to_height, to_par_n, to_par_d, &to_dar_n, &to_dar_d)) {
 +  if (!gst_util_fraction_multiply (out_info.width,
 +          out_info.height, out_info.par_n, out_info.par_d, &to_dar_n,
 +          &to_dar_d)) {
      to_dar_n = to_dar_d = -1;
    }
  
        gint n, d, to_h, to_w;
  
        if (from_dar_n != -1 && from_dar_d != -1
 -          && gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_n,
 -              to_par_d, &n, &d)) {
 -        to_h = gst_util_uint64_scale_int (videoscale->to_width, d, n);
 -        if (to_h <= videoscale->to_height) {
 -          videoscale->borders_h = videoscale->to_height - to_h;
 +          && gst_util_fraction_multiply (from_dar_n, from_dar_d, out_info.par_n,
 +              out_info.par_d, &n, &d)) {
 +        to_h = gst_util_uint64_scale_int (out_info.width, d, n);
 +        if (to_h <= out_info.height) {
 +          videoscale->borders_h = out_info.height - to_h;
            videoscale->borders_w = 0;
          } else {
 -          to_w = gst_util_uint64_scale_int (videoscale->to_height, n, d);
 -          g_assert (to_w <= videoscale->to_width);
 +          to_w = gst_util_uint64_scale_int (out_info.height, n, d);
 +          g_assert (to_w <= out_info.width);
            videoscale->borders_h = 0;
 -          videoscale->borders_w = videoscale->to_width - to_w;
 +          videoscale->borders_w = out_info.width - to_w;
          }
        } else {
          GST_WARNING_OBJECT (videoscale, "Can't calculate borders");
  
    if (videoscale->tmp_buf)
      g_free (videoscale->tmp_buf);
 -  videoscale->tmp_buf = g_malloc (videoscale->to_width * 8 * 4);
 +  videoscale->tmp_buf = g_malloc (out_info.width * 8 * 4);
  
    gst_base_transform_set_passthrough (trans,
 -      (videoscale->from_width == videoscale->to_width
 -          && videoscale->from_height == videoscale->to_height));
 +      (in_info.width == out_info.width && in_info.height == out_info.height));
  
 -  GST_DEBUG_OBJECT (videoscale, "from=%dx%d (par=%d/%d dar=%d/%d), size %d "
 -      "-> to=%dx%d (par=%d/%d dar=%d/%d borders=%d:%d), size %d",
 -      videoscale->from_width, videoscale->from_height, from_par_n, from_par_d,
 -      from_dar_n, from_dar_d, videoscale->src_size, videoscale->to_width,
 -      videoscale->to_height, to_par_n, to_par_d, to_dar_n, to_dar_d,
 -      videoscale->borders_w, videoscale->borders_h, videoscale->dest_size);
 +  GST_DEBUG_OBJECT (videoscale, "from=%dx%d (par=%d/%d dar=%d/%d), size %"
 +      G_GSIZE_FORMAT " -> to=%dx%d (par=%d/%d dar=%d/%d borders=%d:%d), "
 +      "size %" G_GSIZE_FORMAT,
 +      in_info.width, in_info.height, out_info.par_n, out_info.par_d,
 +      from_dar_n, from_dar_d, in_info.size, out_info.width,
 +      out_info.height, out_info.par_n, out_info.par_d, to_dar_n, to_dar_d,
 +      videoscale->borders_w, videoscale->borders_h, out_info.size);
  
 -done:
 -  return ret;
 +  videoscale->from_info = in_info;
 +  videoscale->to_info = out_info;
 +
 +  return TRUE;
 +
 +  /* ERRORS */
 +invalid_formats:
 +  {
 +    GST_DEBUG_OBJECT (videoscale, "could not parse formats");
 +    return FALSE;
 +  }
  }
  
  static gboolean
  gst_video_scale_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
 -    guint * size)
 +    gsize * size)
  {
 -  GstVideoFormat format;
 -  gint width, height;
 +  GstVideoInfo info;
  
 -  if (!gst_video_format_parse_caps (caps, &format, &width, &height))
 +  if (!gst_video_info_from_caps (&info, caps))
      return FALSE;
  
 -  *size = gst_video_format_get_size (format, width, height);
 +  *size = info.size;
  
    return TRUE;
  }
@@@ -900,22 -986,20 +995,22 @@@ done
  }
  
  static void
 -gst_video_scale_setup_vs_image (VSImage * image, GstVideoFormat format,
 -    gint component, gint width, gint height, gint b_w, gint b_h, uint8_t * data)
 +gst_video_scale_setup_vs_image (VSImage * image, GstVideoFrame * frame,
 +    gint component, gint b_w, gint b_h)
  {
 -  image->real_width =
 -      gst_video_format_get_component_width (format, component, width);
 -  image->real_height =
 -      gst_video_format_get_component_height (format, component, height);
 -  image->width =
 -      gst_video_format_get_component_width (format, component, MAX (1,
 -          width - b_w));
 -  image->height =
 -      gst_video_format_get_component_height (format, component, MAX (1,
 -          height - b_h));
 -  image->stride = gst_video_format_get_row_stride (format, component, width);
 +  GstVideoFormat format;
 +  gint width, height;
 +
 +  format = GST_VIDEO_FRAME_FORMAT (frame);
 +  width = GST_VIDEO_FRAME_WIDTH (frame);
 +  height = GST_VIDEO_FRAME_HEIGHT (frame);
 +
 +  image->real_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, component);
 +  image->real_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, component);
 +  image->width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (frame->info.finfo,
 +      component, MAX (1, width - b_w));
 +  image->height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (frame->info.finfo,
 +      component, MAX (1, height - b_h));
  
    image->border_top = (image->real_height - image->height) / 2;
    image->border_bottom = image->real_height - image->height - image->border_top;
      image->border_right = image->real_width - image->width - image->border_left;
    }
  
 -  if (format == GST_VIDEO_FORMAT_I420
 -      || format == GST_VIDEO_FORMAT_YV12
 -      || format == GST_VIDEO_FORMAT_Y444
 -      || format == GST_VIDEO_FORMAT_Y42B || format == GST_VIDEO_FORMAT_Y41B) {
 -    image->real_pixels = data + gst_video_format_get_component_offset (format,
 -        component, width, height);
 -  } else {
 -    g_assert (component == 0);
 -    image->real_pixels = data;
 -  }
 +  image->real_pixels = frame->data[component];
 +  image->stride = frame->info.stride[component];
  
    image->pixels =
        image->real_pixels + image->border_top * image->stride +
 -      image->border_left * gst_video_format_get_pixel_stride (format,
 -      component);
 +      image->border_left * GST_VIDEO_FRAME_COMP_PSTRIDE (frame, component);
  }
  
  static const guint8 *
@@@ -1009,41 -1102,56 +1104,41 @@@ gst_video_scale_transform (GstBaseTrans
  {
    GstVideoScale *videoscale = GST_VIDEO_SCALE (trans);
    GstFlowReturn ret = GST_FLOW_OK;
 -  VSImage dest = { NULL, };
 -  VSImage src = { NULL, };
 -  VSImage dest_u = { NULL, };
 -  VSImage dest_v = { NULL, };
 -  VSImage src_u = { NULL, };
 -  VSImage src_v = { NULL, };
 +  GstVideoFrame in_frame, out_frame;
 +  VSImage dest[4] = { {NULL,}, };
 +  VSImage src[4] = { {NULL,}, };
    gint method;
 -  const guint8 *black = _get_black_for_format (videoscale->format);
 +  const guint8 *black;
    gboolean add_borders;
 +  GstVideoFormat format;
 +  gint i;
  
    GST_OBJECT_LOCK (videoscale);
    method = videoscale->method;
    add_borders = videoscale->add_borders;
    GST_OBJECT_UNLOCK (videoscale);
  
 -  if (videoscale->from_width == 1) {
 +  format = GST_VIDEO_INFO_FORMAT (&videoscale->from_info);
 +  black = _get_black_for_format (format);
 +
 +  if (videoscale->from_info.width == 1) {
      method = GST_VIDEO_SCALE_NEAREST;
    }
    if (method == GST_VIDEO_SCALE_4TAP &&
 -      (videoscale->from_width < 4 || videoscale->from_height < 4)) {
 +      (videoscale->from_info.width < 4 || videoscale->from_info.height < 4)) {
      method = GST_VIDEO_SCALE_BILINEAR;
    }
  
 -  gst_video_scale_setup_vs_image (&src, videoscale->format, 0,
 -      videoscale->from_width, videoscale->from_height, 0, 0,
 -      GST_BUFFER_DATA (in));
 -  gst_video_scale_setup_vs_image (&dest, videoscale->format, 0,
 -      videoscale->to_width, videoscale->to_height, videoscale->borders_w,
 -      videoscale->borders_h, GST_BUFFER_DATA (out));
 -
 -  if (videoscale->format == GST_VIDEO_FORMAT_I420
 -      || videoscale->format == GST_VIDEO_FORMAT_YV12
 -      || videoscale->format == GST_VIDEO_FORMAT_Y444
 -      || videoscale->format == GST_VIDEO_FORMAT_Y42B
 -      || videoscale->format == GST_VIDEO_FORMAT_Y41B) {
 -    gst_video_scale_setup_vs_image (&src_u, videoscale->format, 1,
 -        videoscale->from_width, videoscale->from_height, 0, 0,
 -        GST_BUFFER_DATA (in));
 -    gst_video_scale_setup_vs_image (&src_v, videoscale->format, 2,
 -        videoscale->from_width, videoscale->from_height, 0, 0,
 -        GST_BUFFER_DATA (in));
 -    gst_video_scale_setup_vs_image (&dest_u, videoscale->format, 1,
 -        videoscale->to_width, videoscale->to_height, videoscale->borders_w,
 -        videoscale->borders_h, GST_BUFFER_DATA (out));
 -    gst_video_scale_setup_vs_image (&dest_v, videoscale->format, 2,
 -        videoscale->to_width, videoscale->to_height, videoscale->borders_w,
 -        videoscale->borders_h, GST_BUFFER_DATA (out));
 +  gst_video_frame_map (&in_frame, &videoscale->from_info, in, GST_MAP_READ);
 +  gst_video_frame_map (&out_frame, &videoscale->to_info, out, GST_MAP_WRITE);
 +
 +  for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&in_frame); i++) {
 +    gst_video_scale_setup_vs_image (&src[i], &in_frame, i, 0, 0);
 +    gst_video_scale_setup_vs_image (&dest[i], &out_frame, i,
 +        videoscale->borders_w, videoscale->borders_h);
    }
  
 -  switch (videoscale->format) {
 +  switch (format) {
      case GST_VIDEO_FORMAT_RGBx:
      case GST_VIDEO_FORMAT_xRGB:
      case GST_VIDEO_FORMAT_BGRx:
      case GST_VIDEO_FORMAT_ABGR:
      case GST_VIDEO_FORMAT_AYUV:
        if (add_borders)
 -        vs_fill_borders_RGBA (&dest, black);
 +        vs_fill_borders_RGBA (&dest[0], black);
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_RGBA (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_nearest_RGBA (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_RGBA (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_linear_RGBA (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_RGBA (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_4tap_RGBA (&dest[0], &src[0], videoscale->tmp_buf);
            break;
 -          vs_image_scale_lanczos_AYUV (&dest, &src, videoscale->tmp_buf,
+         case GST_VIDEO_SCALE_LANCZOS:
++          vs_image_scale_lanczos_AYUV (&dest[0], &src[0], videoscale->tmp_buf,
+               videoscale->sharpness, videoscale->dither, videoscale->submethod,
+               videoscale->envelope, videoscale->sharpen);
+           break;
          default:
            goto unknown_mode;
        }
      case GST_VIDEO_FORMAT_ARGB64:
      case GST_VIDEO_FORMAT_AYUV64:
        if (add_borders)
 -        vs_fill_borders_AYUV64 (&dest, black);
 +        vs_fill_borders_AYUV64 (&dest[0], black);
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_AYUV64 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_nearest_AYUV64 (&dest[0], &src[0],
 +              videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_AYUV64 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_linear_AYUV64 (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_AYUV64 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_4tap_AYUV64 (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          default:
            goto unknown_mode;
      case GST_VIDEO_FORMAT_BGR:
      case GST_VIDEO_FORMAT_v308:
        if (add_borders)
 -        vs_fill_borders_RGB (&dest, black);
 +        vs_fill_borders_RGB (&dest[0], black);
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_RGB (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_nearest_RGB (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_RGB (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_linear_RGB (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_RGB (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_4tap_RGB (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          default:
            goto unknown_mode;
      case GST_VIDEO_FORMAT_YUY2:
      case GST_VIDEO_FORMAT_YVYU:
        if (add_borders)
 -        vs_fill_borders_YUYV (&dest, black);
 +        vs_fill_borders_YUYV (&dest[0], black);
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_YUYV (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_nearest_YUYV (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_YUYV (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_linear_YUYV (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_YUYV (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_4tap_YUYV (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          default:
            goto unknown_mode;
        break;
      case GST_VIDEO_FORMAT_UYVY:
        if (add_borders)
 -        vs_fill_borders_UYVY (&dest, black);
 +        vs_fill_borders_UYVY (&dest[0], black);
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_UYVY (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_nearest_UYVY (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_UYVY (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_linear_UYVY (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_UYVY (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_4tap_UYVY (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          default:
            goto unknown_mode;
      case GST_VIDEO_FORMAT_Y800:
      case GST_VIDEO_FORMAT_GRAY8:
        if (add_borders)
 -        vs_fill_borders_Y (&dest, black);
 +        vs_fill_borders_Y (&dest[0], black);
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_nearest_Y (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_linear_Y (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_Y (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_4tap_Y (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          default:
            goto unknown_mode;
      case GST_VIDEO_FORMAT_GRAY16_BE:
      case GST_VIDEO_FORMAT_Y16:
        if (add_borders)
 -        vs_fill_borders_Y16 (&dest, 0);
 +        vs_fill_borders_Y16 (&dest[0], 0);
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_Y16 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_nearest_Y16 (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_Y16 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_linear_Y16 (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_Y16 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_4tap_Y16 (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          default:
            goto unknown_mode;
      case GST_VIDEO_FORMAT_Y42B:
      case GST_VIDEO_FORMAT_Y41B:
        if (add_borders) {
 -        vs_fill_borders_Y (&dest, black);
 -        vs_fill_borders_Y (&dest_u, black + 1);
 -        vs_fill_borders_Y (&dest_v, black + 2);
 +        vs_fill_borders_Y (&dest[0], black);
 +        vs_fill_borders_Y (&dest[1], black + 1);
 +        vs_fill_borders_Y (&dest[2], black + 2);
        }
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf);
 -          vs_image_scale_nearest_Y (&dest_u, &src_u, videoscale->tmp_buf);
 -          vs_image_scale_nearest_Y (&dest_v, &src_v, videoscale->tmp_buf);
 +          vs_image_scale_nearest_Y (&dest[0], &src[0], videoscale->tmp_buf);
 +          vs_image_scale_nearest_Y (&dest[1], &src[1], videoscale->tmp_buf);
 +          vs_image_scale_nearest_Y (&dest[2], &src[2], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf);
 -          vs_image_scale_linear_Y (&dest_u, &src_u, videoscale->tmp_buf);
 -          vs_image_scale_linear_Y (&dest_v, &src_v, videoscale->tmp_buf);
 +          vs_image_scale_linear_Y (&dest[0], &src[0], videoscale->tmp_buf);
 +          vs_image_scale_linear_Y (&dest[1], &src[1], videoscale->tmp_buf);
 +          vs_image_scale_linear_Y (&dest[2], &src[2], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_Y (&dest, &src, videoscale->tmp_buf);
 -          vs_image_scale_4tap_Y (&dest_u, &src_u, videoscale->tmp_buf);
 -          vs_image_scale_4tap_Y (&dest_v, &src_v, videoscale->tmp_buf);
 +          vs_image_scale_4tap_Y (&dest[0], &src[0], videoscale->tmp_buf);
 +          vs_image_scale_4tap_Y (&dest[1], &src[1], videoscale->tmp_buf);
 +          vs_image_scale_4tap_Y (&dest[2], &src[2], videoscale->tmp_buf);
            break;
 -          vs_image_scale_lanczos_Y (&dest, &src, videoscale->tmp_buf,
+         case GST_VIDEO_SCALE_LANCZOS:
 -          vs_image_scale_lanczos_Y (&dest_u, &src_u, videoscale->tmp_buf,
++          vs_image_scale_lanczos_Y (&dest[0], &src[0], videoscale->tmp_buf,
+               videoscale->sharpness, videoscale->dither, videoscale->submethod,
+               videoscale->envelope, videoscale->sharpen);
 -          vs_image_scale_lanczos_Y (&dest_v, &src_v, videoscale->tmp_buf,
++          vs_image_scale_lanczos_Y (&dest[1], &src[1], videoscale->tmp_buf,
+               videoscale->sharpness, videoscale->dither, videoscale->submethod,
+               videoscale->envelope, videoscale->sharpen);
++          vs_image_scale_lanczos_Y (&dest[2], &src[2], videoscale->tmp_buf,
+               videoscale->sharpness, videoscale->dither, videoscale->submethod,
+               videoscale->envelope, videoscale->sharpen);
+           break;
          default:
            goto unknown_mode;
        }
        break;
      case GST_VIDEO_FORMAT_RGB16:
        if (add_borders)
 -        vs_fill_borders_RGB565 (&dest, black);
 +        vs_fill_borders_RGB565 (&dest[0], black);
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_RGB565 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_nearest_RGB565 (&dest[0], &src[0],
 +              videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_RGB565 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_linear_RGB565 (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_RGB565 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_4tap_RGB565 (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          default:
            goto unknown_mode;
        break;
      case GST_VIDEO_FORMAT_RGB15:
        if (add_borders)
 -        vs_fill_borders_RGB555 (&dest, black);
 +        vs_fill_borders_RGB555 (&dest[0], black);
        switch (method) {
          case GST_VIDEO_SCALE_NEAREST:
 -          vs_image_scale_nearest_RGB555 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_nearest_RGB555 (&dest[0], &src[0],
 +              videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_BILINEAR:
 -          vs_image_scale_linear_RGB555 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_linear_RGB555 (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          case GST_VIDEO_SCALE_4TAP:
 -          vs_image_scale_4tap_RGB555 (&dest, &src, videoscale->tmp_buf);
 +          vs_image_scale_4tap_RGB555 (&dest[0], &src[0], videoscale->tmp_buf);
            break;
          default:
            goto unknown_mode;
        goto unsupported;
    }
  
 -  GST_LOG_OBJECT (videoscale, "pushing buffer of %d bytes",
 -      GST_BUFFER_SIZE (out));
 +  GST_LOG_OBJECT (videoscale, "pushing buffer of %" G_GSIZE_FORMAT " bytes",
 +      gst_buffer_get_size (out));
 +
 +done:
 +  gst_video_frame_unmap (&out_frame);
 +  gst_video_frame_unmap (&in_frame);
  
    return ret;
  
  unsupported:
    {
      GST_ELEMENT_ERROR (videoscale, STREAM, NOT_IMPLEMENTED, (NULL),
 -        ("Unsupported format %d for scaling method %d",
 -            videoscale->format, method));
 -    return GST_FLOW_ERROR;
 +        ("Unsupported format %d for scaling method %d", format, method));
 +    ret = GST_FLOW_ERROR;
 +    goto done;
    }
  unknown_mode:
    {
      GST_ELEMENT_ERROR (videoscale, STREAM, NOT_IMPLEMENTED, (NULL),
          ("Unknown scaling method %d", videoscale->method));
 -    return GST_FLOW_ERROR;
 +    ret = GST_FLOW_ERROR;
 +    goto done;
    }
  }
  
@@@ -1294,12 -1410,11 +1405,12 @@@ gst_video_scale_src_event (GstBaseTrans
        structure = (GstStructure *) gst_event_get_structure (event);
        if (gst_structure_get_double (structure, "pointer_x", &a)) {
          gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
 -            a * videoscale->from_width / videoscale->to_width, NULL);
 +            a * videoscale->from_info.width / videoscale->to_info.width, NULL);
        }
        if (gst_structure_get_double (structure, "pointer_y", &a)) {
          gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
 -            a * videoscale->from_height / videoscale->to_height, NULL);
 +            a * videoscale->from_info.height / videoscale->to_info.height,
 +            NULL);
        }
        break;
      default:
@@@ -47,13 -47,15 +47,15 @@@ GST_DEBUG_CATEGORY_EXTERN (video_scale_
   * @GST_VIDEO_SCALE_NEAREST: use nearest neighbour scaling (fast and ugly)
   * @GST_VIDEO_SCALE_BILINEAR: use bilinear scaling (slower but prettier).
   * @GST_VIDEO_SCALE_4TAP: use a 4-tap filter for scaling (slow).
+  * @GST_VIDEO_SCALE_LANCZOS: use a multitap Lanczos filter for scaling (slow).
   *
   * The videoscale method to use.
   */
  typedef enum {
    GST_VIDEO_SCALE_NEAREST,
    GST_VIDEO_SCALE_BILINEAR,
-   GST_VIDEO_SCALE_4TAP
+   GST_VIDEO_SCALE_4TAP,
+   GST_VIDEO_SCALE_LANCZOS
  } GstVideoScaleMethod;
  
  typedef struct _GstVideoScale GstVideoScale;
@@@ -67,12 -69,23 +69,18 @@@ typedef struct _GstVideoScaleClass GstV
  struct _GstVideoScale {
    GstVideoFilter element;
  
+   /* properties */
    GstVideoScaleMethod method;
    gboolean add_borders;
+   double sharpness;
+   double sharpen;
+   gboolean dither;
+   int submethod;
+   double envelope;
  
    /* negotiated stuff */
 -  GstVideoFormat format;
 -  gint to_width;
 -  gint to_height;
 -  gint from_width;
 -  gint from_height;
 -  guint src_size;
 -  guint dest_size;
 +  GstVideoInfo from_info;
 +  GstVideoInfo to_info;
  
    gint borders_h;
    gint borders_w;
@@@ -137,6 -137,8 +137,8 @@@ GST_START_TEST (test_target_naming
  {
    GstEncodingTarget *target;
  
+   gst_debug_set_threshold_for_name ("default", GST_LEVEL_NONE);
    /* NULL values */
    ASSERT_CRITICAL (target = gst_encoding_target_new (NULL, NULL, NULL, NULL));
    fail_if (target != NULL);
@@@ -239,7 -241,8 +241,7 @@@ create_saveload_target (const gchar * t
  
    caps = gst_caps_from_string ("video/x-glitter,sparkling=True");
    caps2 =
 -      gst_caps_from_string
 -      ("video/x-raw-yuv,width=640,height=480,framerate=15/1");
 +      gst_caps_from_string ("video/x-raw,width=640,height=480,framerate=15/1");
    sprof = (GstEncodingProfile *)
        gst_encoding_video_profile_new (caps, "seriously glittery", caps2, 0);
    gst_encoding_video_profile_set_variableframerate ((GstEncodingVideoProfile *)
@@@ -288,8 -291,7 +290,8 @@@ GST_START_TEST (test_saving_profile
    fail_unless (gst_encoding_target_save (orig, NULL));
  
    /* Check we can load it */
 -  profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
 +  profile_file_name =
 +      g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
        "encoding-profiles", "herding", "myponytarget2.gep", NULL);
    GST_DEBUG ("Loading target from '%s'", profile_file_name);
    loaded = gst_encoding_target_load_from_file (profile_file_name, NULL);
@@@ -375,7 -377,8 +377,7 @@@ test_individual_target (GstEncodingTarg
    GST_DEBUG ("Checking the container profile has the video//x-glitter stream");
    tmpcaps = gst_caps_from_string ("video/x-glitter,sparkling=True");
    tmpcaps2 =
 -      gst_caps_from_string
 -      ("video/x-raw-yuv,width=640,height=480,framerate=15/1");
 +      gst_caps_from_string ("video/x-raw,width=640,height=480,framerate=15/1");
    sprof2 = (GstEncodingProfile *)
        gst_encoding_video_profile_new (tmpcaps, "seriously glittery", tmpcaps2,
        0);
@@@ -395,8 -398,10 +397,10 @@@ GST_START_TEST (test_loading_profile
    GstEncodingProfile *profile;
    GstCaps *tmpcaps;
    GValue strvalue = { 0, };
 -  GValue miniobjectvalue = { 0, };
 +  GValue objectvalue = { 0, };
  
+   gst_debug_set_threshold_for_name ("default", GST_LEVEL_NONE);
    /* Test loading using short method and all arguments */
    target = gst_encoding_target_load ("myponytarget", "herding", NULL);
    fail_unless (target != NULL);
    gst_encoding_target_unref (target);
  
    /* Test loading using fully specified path */
 -  profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
 +  profile_file_name =
 +      g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
        "encoding-profiles", "herding", "myponytarget.gep", NULL);
  
    GST_DEBUG ("Loading target from '%s'", profile_file_name);
  
    /* For my next trick, I will need the assistance of a GValue */
    g_value_init (&strvalue, G_TYPE_STRING);
 -  g_value_init (&miniobjectvalue, GST_TYPE_ENCODING_PROFILE);
 +  g_value_init (&objectvalue, GST_TYPE_ENCODING_PROFILE);
    g_value_set_static_string (&strvalue, "myponytarget/pony");
 -  fail_unless (g_value_transform (&strvalue, &miniobjectvalue));
 -  profile = (GstEncodingProfile *) gst_value_dup_mini_object (&miniobjectvalue);
 +  fail_unless (g_value_transform (&strvalue, &objectvalue));
 +  profile = (GstEncodingProfile *) g_value_dup_object (&objectvalue);
    fail_if (profile == NULL);
    g_value_unset (&strvalue);
 -  g_value_unset (&miniobjectvalue);
 +  g_value_unset (&objectvalue);
    tmpcaps = gst_caps_from_string ("animal/x-pony");
    CHECK_PROFILE (profile, "pony", "I don't want a description !", tmpcaps, NULL,
        0, 0);
@@@ -489,7 -493,7 +493,7 @@@ GST_START_TEST (test_target_list
    /* If tmp is NULL, it means we iterated the whole list without finding
     * our target */
    fail_if (tmp == NULL);
 -  g_list_foreach (targets, (GFunc) gst_mini_object_unref, NULL);
 +  g_list_foreach (targets, (GFunc) g_object_unref, NULL);
    g_list_free (targets);
  
    /* Try getting all available targets without a specified category */
    /* If tmp is NULL, it means we iterated the whole list without finding
     * our target */
    fail_if (tmp == NULL);
 -  g_list_foreach (targets, (GFunc) gst_mini_object_unref, NULL);
 +  g_list_foreach (targets, (GFunc) g_object_unref, NULL);
    g_list_free (targets);
  }
  
@@@ -534,7 -538,7 +538,7 @@@ parent=pony\n
  type=video\n\
  preset=seriously glittery\n\
  format=video/x-glitter,sparkling=True\n\
 -restriction=video/x-raw-yuv,width=640,height=480,framerate=15/1\n\
 +restriction=video/x-raw,width=640,height=480,framerate=15/1\n\
  presence=0\n\
  variableframerate=true\n\
  ";
@@@ -544,13 -548,11 +548,13 @@@ remove_profile_file (void
  {
    gchar *profile_file_name;
  
 -  profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
 +  profile_file_name =
 +      g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
        "encoding-profiles", "herding", "myponytarget.gep", NULL);
    g_unlink (profile_file_name);
    g_free (profile_file_name);
 -  profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
 +  profile_file_name =
 +      g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
        "encoding-profiles", "herding", "myponytarget2.gep", NULL);
    g_unlink (profile_file_name);
    g_free (profile_file_name);
@@@ -564,10 -566,10 +568,10 @@@ create_profile_file (void
    GError *error = NULL;
  
    profile_dir =
 -      g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
 +      g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
        "encoding-profiles", "herding", NULL);
    profile_file_name =
 -      g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
 +      g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
        "encoding-profiles", "herding", "myponytarget.gep", NULL);
    g_mkdir_with_parents (profile_dir, S_IRUSR | S_IWUSR | S_IXUSR);
    if (!g_file_set_contents (profile_file_name, profile_string,
@@@ -599,7 -601,7 +603,7 @@@ profile_suite (void
    gchar *gst_dir;
  
    /* cehck if we can create profiles */
 -  gst_dir = g_build_filename (g_get_home_dir (), ".gstreamer-0.10", NULL);
 +  gst_dir = g_build_filename (g_get_user_data_dir (), "gstreamer-0.11", NULL);
    can_write = (g_access (gst_dir, R_OK | W_OK | X_OK) == 0);
    g_free (gst_dir);
  
diff --combined tests/check/libs/tag.c
@@@ -408,8 -408,6 +408,8 @@@ GST_START_TEST (test_vorbis_tags
    /* now, while we still have a taglist, test _to_vorbiscomment_buffer() */
    {
      GstBuffer *buf1, *buf2;
 +    guint8 *data1, *data2;
 +    gsize size1, size2;
  
      ASSERT_CRITICAL (gst_tag_list_to_vorbiscomment_buffer (NULL,
              (const guint8 *) "x", 1, "x"));
          (const guint8 *) "foo", 3, NULL);
      fail_unless (buf2 != NULL);
  
 -    fail_unless (memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2) + 3,
 -            GST_BUFFER_SIZE (buf1)) == 0);
 +    data1 = gst_buffer_map (buf1, &size1, NULL, GST_MAP_READ);
 +    data2 = gst_buffer_map (buf2, &size2, NULL, GST_MAP_READ);
 +
 +    fail_unless (memcmp (data1, data2 + 3, size1) == 0);
 +
 +    gst_buffer_unmap (buf2, data2, size2);
 +    gst_buffer_unmap (buf1, data1, size1);
  
      gst_buffer_unref (buf1);
      gst_buffer_unref (buf2);
      gchar *vendor = NULL;
  
      buf = gst_buffer_new ();
 -    GST_BUFFER_DATA (buf) = (guint8 *) speex_comments_buf1;
 -    GST_BUFFER_SIZE (buf) = sizeof (speex_comments_buf1);
 +    gst_buffer_take_memory (buf, -1,
 +        gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
 +            (gpointer) speex_comments_buf1, NULL,
 +            sizeof (speex_comments_buf1), 0, sizeof (speex_comments_buf1)));
  
      /* make sure it doesn't memcmp over the end of the buffer */
      fail_unless (gst_tag_list_from_vorbiscomment_buffer (buf,
      gchar *vendor = NULL;
  
      buf = gst_buffer_new ();
 -    GST_BUFFER_DATA (buf) = (guint8 *) vorbis_comments_buf;
 -    GST_BUFFER_SIZE (buf) = sizeof (vorbis_comments_buf);
 +    gst_buffer_take_memory (buf, -1,
 +        gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
 +            (gpointer) vorbis_comments_buf, NULL,
 +            sizeof (vorbis_comments_buf), 0, sizeof (vorbis_comments_buf)));
  
      /* make sure it doesn't memcmp over the end of the buffer */
      fail_unless (gst_tag_list_from_vorbiscomment_buffer (buf,
@@@ -776,6 -765,8 +776,8 @@@ GST_START_TEST (test_license_utils
    gchar *path, *data = NULL;
    gsize data_len;
  
+   gst_debug_set_threshold_for_name ("tag-licenses", GST_LEVEL_NONE);
    /* test jurisdiction-specific license */
    fail_unless_equals_int (gst_tag_get_license_flags (SPECIFIC_L), 0x01010703);
    fail_unless_equals_string (gst_tag_get_license_nick (SPECIFIC_L),
@@@ -952,7 -943,7 +954,7 @@@ GST_START_TEST (test_xmp_formatting
    GstTagList *list;
    GstBuffer *buf;
    const gchar *text;
 -  guint len;
 +  gsize len;
  
    /* test data */
    list = gst_tag_list_new_full (GST_TAG_TITLE, "test title",
    buf = gst_tag_list_to_xmp_buffer (list, FALSE);
    fail_unless (buf != NULL);
  
 -  text = (const gchar *) GST_BUFFER_DATA (buf);
 -  len = GST_BUFFER_SIZE (buf);
 +  text = gst_buffer_map (buf, &len, NULL, GST_MAP_READ);
  
    /* check the content */
    fail_unless (g_strrstr_len (text, len, "<?xpacket begin") == text);
    fail_unless (g_strrstr_len (text, len, ">keyword1<") != NULL);
    fail_unless (g_strrstr_len (text, len, ">keyword2<") != NULL);
    fail_unless (g_strrstr_len (text, len, "<?xpacket end") != NULL);
 +  gst_buffer_unmap (buf, (gpointer) text, len);
  
    gst_buffer_unref (buf);
    gst_tag_list_free (list);
@@@ -1010,18 -1001,16 +1012,18 @@@ GST_START_TEST (test_xmp_parsing
    };
  
    /* test data */
 -  buf = gst_buffer_new ();
 -
    i = 0;
    while (test_data[i].xmp_data) {
 +    gsize len;
 +
      GST_DEBUG ("trying test-data %u", i);
  
      text = g_strconcat (xmp_header, test_data[i].xmp_data, xmp_footer, NULL);
 -    GST_BUFFER_DATA (buf) = (guint8 *) text;
 -    GST_BUFFER_SIZE (buf) = strlen (text) + 1;
  
 +    buf = gst_buffer_new ();
 +    len = strlen (text) + 1;
 +    gst_buffer_take_memory (buf, -1,
 +        gst_memory_new_wrapped (0, text, NULL, len, 0, len));
  
      list = gst_tag_list_from_xmp_buffer (buf);
      if (test_data[i].result_size >= 0) {
      if (list)
        gst_tag_list_free (list);
  
 +    gst_buffer_unref (buf);
      g_free (text);
      i++;
    }
 -
 -  gst_buffer_unref (buf);
  }
  
  GST_END_TEST;
@@@ -1466,7 -1456,6 +1468,7 @@@ GST_START_TEST (test_exif_tags_serializ
    GstBuffer *buf = NULL;
    gint i;
    GstTagList *taglist;
 +  guint8 *data;
  
    gst_tag_register_musicbrainz_tags ();
  
  
    g_value_init (&value, GST_TYPE_BUFFER);
    buf = gst_buffer_new_and_alloc (1024);
 +  data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
    for (i = 0; i < 1024; i++)
 -    GST_BUFFER_DATA (buf)[i] = i % 255;
 +    data[i] = i % 255;
 +  gst_buffer_unmap (buf, data, 1024);
    gst_value_set_buffer (&value, buf);
    gst_buffer_unref (buf);
    do_simple_exif_tag_serialization_deserialization (GST_TAG_APPLICATION_DATA,
diff --combined tests/check/libs/video.c
@@@ -358,49 -358,11 +358,49 @@@ video_format_is_packed (GstVideoFormat 
    return FALSE;
  }
  
 +GST_START_TEST (test_video_formats_all)
 +{
 +  GstStructure *s;
 +  const GValue *val, *list_val;
 +  GstCaps *caps;
 +  guint num, n, num_formats;
 +
 +  num_formats = 100;
 +  fail_unless (gst_video_format_to_string (num_formats) == NULL);
 +  while (gst_video_format_to_string (num_formats) == NULL)
 +    --num_formats;
 +  GST_INFO ("number of known video formats: %d", num_formats);
 +
 +  caps = gst_caps_from_string ("video/x-raw, format=" GST_VIDEO_FORMATS_ALL);
 +  s = gst_caps_get_structure (caps, 0);
 +  val = gst_structure_get_value (s, "format");
 +  fail_unless (val != NULL);
 +  fail_unless (GST_VALUE_HOLDS_LIST (val));
 +  num = gst_value_list_get_size (val);
 +  fail_unless (num > 0);
 +  for (n = 0; n < num; ++n) {
 +    const gchar *fmt_str;
 +
 +    list_val = gst_value_list_get_value (val, n);
 +    fail_unless (G_VALUE_HOLDS_STRING (list_val));
 +    fmt_str = g_value_get_string (list_val);
 +    GST_INFO ("format: %s", fmt_str);
 +    fail_if (gst_video_format_from_string (fmt_str) ==
 +        GST_VIDEO_FORMAT_UNKNOWN);
 +  }
 +  fail_unless_equals_int (num, num_formats);
 +
 +  gst_caps_unref (caps);
 +}
 +
 +GST_END_TEST;
 +
  GST_START_TEST (test_video_formats)
  {
    guint i;
  
    for (i = 0; i < G_N_ELEMENTS (fourcc_list); ++i) {
 +    const GstVideoFormatInfo *vf_info;
      GstVideoFormat fmt;
      const gchar *s;
      guint32 fourcc;
      if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
        continue;
  
 -    GST_INFO ("Fourcc %s, packed=%d", fourcc_list[i].fourcc,
 +    vf_info = gst_video_format_get_info (fmt);
 +    fail_unless (vf_info != NULL);
 +
 +    fail_unless_equals_int (GST_VIDEO_FORMAT_INFO_FORMAT (vf_info), fmt);
 +
 +    GST_INFO ("Fourcc %s, packed=%", fourcc_list[i].fourcc,
          gst_video_format_is_packed (fmt));
  
 -    fail_unless (gst_video_format_is_yuv (fmt));
 +    fail_unless (GST_VIDEO_FORMAT_INFO_IS_YUV (vf_info));
  
      /* use any non-NULL pointer so we can compare against NULL */
      {
        paintinfo paintinfo = { 0, };
        fourcc_list[i].paint_setup (&paintinfo, (unsigned char *) s);
        if (paintinfo.ap != NULL) {
 -        fail_unless (gst_video_format_has_alpha (fmt));
 +        fail_unless (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (vf_info));
        } else {
 -        fail_if (gst_video_format_has_alpha (fmt));
 +        fail_if (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (vf_info));
        }
      }
  
      for (w = 1; w <= 65; ++w) {
        for (h = 1; h <= 65; ++h) {
 +        GstVideoInfo vinfo;
          paintinfo paintinfo = { 0, };
          guint off0, off1, off2, off3;
          guint size;
  
          GST_LOG ("%s, %dx%d", fourcc_list[i].fourcc, w, h);
  
 +        gst_video_info_init (&vinfo);
 +        gst_video_info_set_format (&vinfo, fmt, w, h);
 +
          paintinfo.width = w;
          paintinfo.height = h;
          fourcc_list[i].paint_setup (&paintinfo, NULL);
 -        fail_unless_equals_int (gst_video_format_get_row_stride (fmt, 0, w),
 +        fail_unless_equals_int (GST_VIDEO_INFO_COMP_STRIDE (&vinfo, 0),
              paintinfo.ystride);
          if (!gst_video_format_is_packed (fmt)
 -            && !gst_video_format_is_gray (fmt)) {
 +            && !GST_VIDEO_FORMAT_INFO_IS_GRAY (vf_info)) {
            /* planar */
 -          fail_unless_equals_int (gst_video_format_get_row_stride (fmt, 1, w),
 +          fail_unless_equals_int (GST_VIDEO_INFO_COMP_STRIDE (&vinfo, 1),
                paintinfo.ustride);
 -          fail_unless_equals_int (gst_video_format_get_row_stride (fmt, 2, w),
 +          fail_unless_equals_int (GST_VIDEO_INFO_COMP_STRIDE (&vinfo, 2),
                paintinfo.vstride);
            /* check component_width * height against offsets/size somehow? */
          }
  
 -        size = gst_video_format_get_size (fmt, w, h);
 -        off0 = gst_video_format_get_component_offset (fmt, 0, w, h);
 -        off1 = gst_video_format_get_component_offset (fmt, 1, w, h);
 -        off2 = gst_video_format_get_component_offset (fmt, 2, w, h);
 +        size = GST_VIDEO_INFO_SIZE (&vinfo);
 +        off0 = GST_VIDEO_INFO_COMP_OFFSET (&vinfo, 0);
 +        off1 = GST_VIDEO_INFO_COMP_OFFSET (&vinfo, 1);
 +        off2 = GST_VIDEO_INFO_COMP_OFFSET (&vinfo, 2);
  
          fail_unless_equals_int (size, (unsigned long) paintinfo.endptr);
          fail_unless_equals_int (off0, (unsigned long) paintinfo.yp);
          fail_unless_equals_int (off2, (unsigned long) paintinfo.vp);
  
          /* should be 0 if there's no alpha component */
 -        off3 = gst_video_format_get_component_offset (fmt, 3, w, h);
 +        off3 = GST_VIDEO_INFO_COMP_OFFSET (&vinfo, 3);
          fail_unless_equals_int (off3, (unsigned long) paintinfo.ap);
  
          /* some gstvideo checks ... (FIXME: fails for Y41B and Y42B; not sure
              && fmt != GST_VIDEO_FORMAT_Y800) {
            guint cs0, cs1, cs2, cs3;
  
 -          cs0 = gst_video_format_get_component_width (fmt, 0, w) *
 -              gst_video_format_get_component_height (fmt, 0, h);
 -          cs1 = gst_video_format_get_component_width (fmt, 1, w) *
 -              gst_video_format_get_component_height (fmt, 1, h);
 -          cs2 = gst_video_format_get_component_width (fmt, 2, w) *
 -              gst_video_format_get_component_height (fmt, 2, h);
 +          cs0 = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, 0) *
 +              GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, 0);
 +          cs1 = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, 1) *
 +              GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, 1);
 +          cs2 = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, 2) *
 +              GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, 2);
  
            /* GST_LOG ("cs0=%d,cs1=%d,cs2=%d,off0=%d,off1=%d,off2=%d,size=%d",
               cs0, cs1, cs2, off0, off1, off2, size); */
            if (!gst_video_format_is_packed (fmt))
              fail_unless (cs0 <= off1);
  
 -          if (gst_video_format_has_alpha (fmt)) {
 -            cs3 = gst_video_format_get_component_width (fmt, 3, w) *
 -                gst_video_format_get_component_height (fmt, 3, h);
 +          if (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (vinfo.finfo)) {
 +            cs3 = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, 3) *
 +                GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, 2);
              fail_unless (cs3 < size);
              /* U/V/alpha shouldn't take up more space than the Y component */
              fail_if (cs1 > cs0, "cs1 (%d) should be <= cs0 (%d)", cs1, cs0);
@@@ -525,17 -478,11 +525,17 @@@ GST_END_TEST
  
  GST_START_TEST (test_video_formats_rgb)
  {
 +  GstVideoInfo vinfo;
    gint width, height, framerate_n, framerate_d, par_n, par_d;
 -  GstCaps *caps =
 -      gst_video_format_new_caps (GST_VIDEO_FORMAT_RGB, 800, 600, 0, 1, 1, 1);
 +  GstCaps *caps;
    GstStructure *structure;
  
 +  gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_RGB, 800, 600);
 +  vinfo.par_n = 1;
 +  vinfo.par_d = 1;
 +  vinfo.fps_n = 0;
 +  vinfo.fps_d = 1;
 +  caps = gst_video_info_to_caps (&vinfo);
    structure = gst_caps_get_structure (caps, 0);
  
    fail_unless (gst_structure_get_int (structure, "width", &width));
  
  GST_END_TEST;
  
 -GST_START_TEST (test_video_template_caps)
 -{
 -  GstCaps *caps = gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB);
 -  gst_caps_unref (caps);
 -}
 -
 -GST_END_TEST;
 -
 -
  GST_START_TEST (test_dar_calc)
  {
    guint display_ratio_n, display_ratio_d;
@@@ -590,26 -546,27 +590,26 @@@ GST_START_TEST (test_parse_caps_rgb
    } formats[] = {
      /* 24 bit */
      {
 -    GST_VIDEO_CAPS_RGB, GST_VIDEO_FORMAT_RGB}, {
 -    GST_VIDEO_CAPS_BGR, GST_VIDEO_FORMAT_BGR},
 +    GST_VIDEO_CAPS_MAKE ("RGB"), GST_VIDEO_FORMAT_RGB}, {
 +    GST_VIDEO_CAPS_MAKE ("BGR"), GST_VIDEO_FORMAT_BGR},
          /* 32 bit (no alpha) */
      {
 -    GST_VIDEO_CAPS_RGBx, GST_VIDEO_FORMAT_RGBx}, {
 -    GST_VIDEO_CAPS_xRGB, GST_VIDEO_FORMAT_xRGB}, {
 -    GST_VIDEO_CAPS_BGRx, GST_VIDEO_FORMAT_BGRx}, {
 -    GST_VIDEO_CAPS_xBGR, GST_VIDEO_FORMAT_xBGR},
 +    GST_VIDEO_CAPS_MAKE ("RGBx"), GST_VIDEO_FORMAT_RGBx}, {
 +    GST_VIDEO_CAPS_MAKE ("xRGB"), GST_VIDEO_FORMAT_xRGB}, {
 +    GST_VIDEO_CAPS_MAKE ("BGRx"), GST_VIDEO_FORMAT_BGRx}, {
 +    GST_VIDEO_CAPS_MAKE ("xBGR"), GST_VIDEO_FORMAT_xBGR},
          /* 32 bit (with alpha) */
      {
 -    GST_VIDEO_CAPS_RGBA, GST_VIDEO_FORMAT_RGBA}, {
 -    GST_VIDEO_CAPS_ARGB, GST_VIDEO_FORMAT_ARGB}, {
 -    GST_VIDEO_CAPS_BGRA, GST_VIDEO_FORMAT_BGRA}, {
 -    GST_VIDEO_CAPS_ABGR, GST_VIDEO_FORMAT_ABGR}
 +    GST_VIDEO_CAPS_MAKE ("RGBA"), GST_VIDEO_FORMAT_RGBA}, {
 +    GST_VIDEO_CAPS_MAKE ("ARGB"), GST_VIDEO_FORMAT_ARGB}, {
 +    GST_VIDEO_CAPS_MAKE ("BGRA"), GST_VIDEO_FORMAT_BGRA}, {
 +    GST_VIDEO_CAPS_MAKE ("ABGR"), GST_VIDEO_FORMAT_ABGR}
    };
    gint i;
  
    for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
 -    GstVideoFormat fmt = GST_VIDEO_FORMAT_UNKNOWN;
 +    GstVideoInfo vinfo;
      GstCaps *caps, *caps2;
 -    int w = -1, h = -1;
  
      caps = gst_caps_from_string (formats[i].tmpl_caps_string);
      gst_caps_set_simple (caps, "width", G_TYPE_INT, 2 * (i + 1), "height",
  
      GST_DEBUG ("testing caps: %" GST_PTR_FORMAT, caps);
  
 -    fail_unless (gst_video_format_parse_caps (caps, &fmt, &w, &h));
 -    fail_unless_equals_int (fmt, formats[i].fmt);
 -    fail_unless_equals_int (w, 2 * (i + 1));
 -    fail_unless_equals_int (h, i + 1);
 +    gst_video_info_init (&vinfo);
 +    fail_unless (gst_video_info_from_caps (&vinfo, caps));
 +    fail_unless_equals_int (GST_VIDEO_INFO_FORMAT (&vinfo), formats[i].fmt);
 +    fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&vinfo), 2 * (i + 1));
 +    fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&vinfo), i + 1);
  
      /* make sure they're serialised back correctly */
 -    caps2 = gst_video_format_new_caps (fmt, w, h, 15, 1, 1, 1);
 +    caps2 = gst_video_info_to_caps (&vinfo);
      fail_unless (caps != NULL);
      fail_unless (gst_caps_is_equal (caps, caps2));
  
@@@ -665,56 -621,47 +665,58 @@@ GST_END_TEST
  
  GST_START_TEST (test_convert_frame)
  {
 +  GstVideoInfo vinfo;
    GstCaps *from_caps, *to_caps;
    GstBuffer *from_buffer, *to_buffer;
    GError *error = NULL;
    gint i;
    guint8 *data;
  
+   gst_debug_set_threshold_for_name ("default", GST_LEVEL_NONE);
    from_buffer = gst_buffer_new_and_alloc (640 * 480 * 4);
 -  data = GST_BUFFER_DATA (from_buffer);
  
 +  data = gst_buffer_map (from_buffer, NULL, NULL, GST_MAP_WRITE);
    for (i = 0; i < 640 * 480; i++) {
      data[4 * i + 0] = 0;        /* x */
      data[4 * i + 1] = 255;      /* R */
      data[4 * i + 2] = 0;        /* G */
      data[4 * i + 3] = 0;        /* B */
    }
 -  from_caps = gst_video_format_new_caps (GST_VIDEO_FORMAT_xRGB,
 -      640, 480, 25, 1, 1, 1);
 -  gst_buffer_set_caps (from_buffer, from_caps);
 +  gst_buffer_unmap (from_buffer, data, 640 * 480 * 4);
 +
 +  gst_video_info_init (&vinfo);
 +  gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_xRGB, 640, 480);
 +  vinfo.fps_n = 25;
 +  vinfo.fps_d = 1;
 +  vinfo.par_n = 1;
 +  vinfo.par_d = 1;
 +  from_caps = gst_video_info_to_caps (&vinfo);
  
    to_caps =
        gst_caps_from_string
        ("something/that, does=(string)not, exist=(boolean)FALSE");
  
    to_buffer =
 -      gst_video_convert_frame (from_buffer, to_caps, GST_CLOCK_TIME_NONE,
 -      &error);
 +      gst_video_convert_frame (from_buffer, from_caps, to_caps,
 +      GST_CLOCK_TIME_NONE, &error);
    fail_if (to_buffer != NULL);
    fail_unless (error != NULL);
    g_error_free (error);
    error = NULL;
  
    gst_caps_unref (to_caps);
 -  to_caps =
 -      gst_video_format_new_caps (GST_VIDEO_FORMAT_I420, 240, 320, 25, 1, 1, 2);
 +  gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_I420, 240, 320);
 +  vinfo.fps_n = 25;
 +  vinfo.fps_d = 1;
 +  vinfo.par_n = 1;
 +  vinfo.par_d = 2;
 +  to_caps = gst_video_info_to_caps (&vinfo);
 +
    to_buffer =
 -      gst_video_convert_frame (from_buffer, to_caps, GST_CLOCK_TIME_NONE,
 -      &error);
 +      gst_video_convert_frame (from_buffer, from_caps, to_caps,
 +      GST_CLOCK_TIME_NONE, &error);
    fail_unless (to_buffer != NULL);
 -  fail_unless (gst_caps_can_intersect (to_caps, GST_BUFFER_CAPS (to_buffer)));
    fail_unless (error == NULL);
  
    gst_buffer_unref (from_buffer);
@@@ -744,7 -691,6 +746,7 @@@ convert_frame_async_callback (GstBuffe
  
  GST_START_TEST (test_convert_frame_async)
  {
 +  GstVideoInfo vinfo;
    GstCaps *from_caps, *to_caps;
    GstBuffer *from_buffer;
    gint i;
    GMainLoop *loop;
    ConvertFrameContext cf_data = { NULL, NULL, NULL };
  
+   gst_debug_set_threshold_for_name ("default", GST_LEVEL_NONE);
    from_buffer = gst_buffer_new_and_alloc (640 * 480 * 4);
 -  data = GST_BUFFER_DATA (from_buffer);
  
 +  data = gst_buffer_map (from_buffer, NULL, NULL, GST_MAP_WRITE);
    for (i = 0; i < 640 * 480; i++) {
      data[4 * i + 0] = 0;        /* x */
      data[4 * i + 1] = 255;      /* R */
      data[4 * i + 2] = 0;        /* G */
      data[4 * i + 3] = 0;        /* B */
    }
 -  from_caps = gst_video_format_new_caps (GST_VIDEO_FORMAT_xRGB,
 -      640, 480, 25, 1, 1, 1);
 -  gst_buffer_set_caps (from_buffer, from_caps);
 +  gst_buffer_unmap (from_buffer, data, 640 * 480 * 4);
 +
 +  gst_video_info_init (&vinfo);
 +  gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_xRGB, 640, 470);
 +  vinfo.par_n = 1;
 +  vinfo.par_d = 1;
 +  vinfo.fps_n = 25;
 +  vinfo.fps_d = 1;
 +  from_caps = gst_video_info_to_caps (&vinfo);
  
    to_caps =
        gst_caps_from_string
  
    loop = cf_data.loop = g_main_loop_new (NULL, FALSE);
  
 -  gst_video_convert_frame_async (from_buffer, to_caps, GST_CLOCK_TIME_NONE,
 +  gst_video_convert_frame_async (from_buffer, from_caps, to_caps,
 +      GST_CLOCK_TIME_NONE,
        (GstVideoConvertFrameCallback) convert_frame_async_callback, &cf_data,
        NULL);
  
    cf_data.error = NULL;
  
    gst_caps_unref (to_caps);
 -  to_caps =
 -      gst_video_format_new_caps (GST_VIDEO_FORMAT_I420, 240, 320, 25, 1, 1, 2);
 -  gst_video_convert_frame_async (from_buffer, to_caps, GST_CLOCK_TIME_NONE,
 +  gst_video_info_init (&vinfo);
 +  gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_I420, 240, 320);
 +  vinfo.par_n = 1;
 +  vinfo.par_d = 2;
 +  vinfo.fps_n = 25;
 +  vinfo.fps_d = 1;
 +  to_caps = gst_video_info_to_caps (&vinfo);
 +  gst_video_convert_frame_async (from_buffer, from_caps, to_caps,
 +      GST_CLOCK_TIME_NONE,
        (GstVideoConvertFrameCallback) convert_frame_async_callback, &cf_data,
        NULL);
    g_main_loop_run (loop);
    fail_unless (cf_data.buffer != NULL);
 -  fail_unless (gst_caps_can_intersect (to_caps,
 -          GST_BUFFER_CAPS (cf_data.buffer)));
    fail_unless (cf_data.error == NULL);
  
    gst_buffer_unref (from_buffer);
@@@ -817,17 -754,20 +821,17 @@@ GST_END_TEST
  
  GST_START_TEST (test_video_size_from_caps)
  {
 -  gint size;
 -  guint32 fourcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
 -  GstCaps *caps = gst_caps_new_simple ("video/x-raw-yuv",
 -      "format", GST_TYPE_FOURCC, fourcc,
 +  GstVideoInfo vinfo;
 +  GstCaps *caps;
 +
 +  caps = gst_caps_new_simple ("video/x-raw",
 +      "format", G_TYPE_STRING, "YV12",
        "width", G_TYPE_INT, 640,
 -      "height", G_TYPE_INT, 480,
 -      "framerate", GST_TYPE_FRACTION, 25, 1,
 -      NULL);
 +      "height", G_TYPE_INT, 480, "framerate", GST_TYPE_FRACTION, 25, 1, NULL);
  
 -  fail_unless (gst_video_get_size_from_caps (caps, &size));
 -  fail_unless (size ==
 -      gst_video_format_get_size (gst_video_format_from_fourcc (fourcc), 640,
 -          480));
 -  fail_unless (size == (640 * 480 * 12 / 8));
 +  gst_video_info_init (&vinfo);
 +  fail_unless (gst_video_info_from_caps (&vinfo, caps));
 +  fail_unless (GST_VIDEO_INFO_SIZE (&vinfo) == (640 * 480 * 12 / 8));
  
    gst_caps_unref (caps);
  }
@@@ -843,7 -783,7 +847,7 @@@ video_suite (void
    suite_add_tcase (s, tc_chain);
    tcase_add_test (tc_chain, test_video_formats);
    tcase_add_test (tc_chain, test_video_formats_rgb);
 -  tcase_add_test (tc_chain, test_video_template_caps);
 +  tcase_add_test (tc_chain, test_video_formats_all);
    tcase_add_test (tc_chain, test_dar_calc);
    tcase_add_test (tc_chain, test_parse_caps_rgb);
    tcase_add_test (tc_chain, test_events);
@@@ -39,7 -39,7 +39,7 @@@
  #include <gdk/gdkwin32.h>
  #endif
  
 -#include <gst/interfaces/xoverlay.h>
 +#include <gst/interfaces/videooverlay.h>
  
  #if (!GTK_CHECK_VERSION(2, 23, 0) || GTK_CHECK_VERSION(2, 90, 0)) && !GTK_CHECK_VERSION(2, 91, 1)
  #define gtk_combo_box_text_new gtk_combo_box_new_text
@@@ -84,6 -84,8 +84,6 @@@ static gchar *opt_videosink_str
  
  #define N_GRAD 1000.0
  
 -static GList *seekable_pads = NULL;
 -static GList *rate_pads = NULL;
  static GList *seekable_elements = NULL;
  
  static gboolean accurate_seek = FALSE;
@@@ -104,6 -106,7 +104,6 @@@ static GtkAdjustment *adjustment
  static GtkWidget *hscale, *statusbar;
  static guint status_id = 0;
  static gboolean stats = FALSE;
 -static gboolean elem_seek = FALSE;
  static gboolean verbose = FALSE;
  
  static gboolean is_live = FALSE;
@@@ -161,6 -164,16 +161,16 @@@ gst_element_factory_make_or_warn (cons
  {
    GstElement *element = gst_element_factory_make (type, name);
  
+ #ifndef GST_DISABLE_PARSE
+   if (!element) {
+     /* Try parsing it as a pipeline description */
+     element = gst_parse_bin_from_description (type, TRUE, NULL);
+     if (element) {
+       gst_element_set_name (element, name);
+     }
+   }
+ #endif
    if (!element) {
      g_warning ("Failed to create element %s of type %s", name, type);
    }
  }
  
  static void
 -dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
 -{
 -  gchar *padname;
 -  dyn_link *connect = (dyn_link *) data;
 -
 -  padname = gst_pad_get_name (newpad);
 -
 -  if (connect->padname == NULL || !strcmp (padname, connect->padname)) {
 -    if (connect->bin)
 -      gst_bin_add (GST_BIN (pipeline), connect->bin);
 -    gst_pad_link (newpad, connect->target);
 -
 -    //seekable_pads = g_list_prepend (seekable_pads, newpad);
 -    rate_pads = g_list_prepend (rate_pads, newpad);
 -  }
 -  g_free (padname);
 -}
 -
 -static void
 -setup_dynamic_link (GstElement * element, const gchar * padname,
 -    GstPad * target, GstElement * bin)
 -{
 -  dyn_link *connect;
 -
 -  connect = g_new0 (dyn_link, 1);
 -  connect->padname = g_strdup (padname);
 -  connect->target = target;
 -  connect->bin = bin;
 -
 -  g_signal_connect (G_OBJECT (element), "pad-added", G_CALLBACK (dynamic_link),
 -      connect);
 -}
 -
 -static GstElement *
 -make_mod_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline;
 -  GstElement *src, *decoder, *audiosink;
 -  GstPad *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  decoder = gst_element_factory_make_or_warn ("modplug", "decoder");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "sink");
 -  //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
 -
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), decoder);
 -  gst_bin_add (GST_BIN (pipeline), audiosink);
 -
 -  gst_element_link (src, decoder);
 -  gst_element_link (decoder, audiosink);
 -
 -  seekable = gst_element_get_static_pad (decoder, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_dv_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline;
 -  GstElement *src, *demux, *decoder, *audiosink, *videosink;
 -  GstElement *a_queue, *v_queue;
 -  GstPad *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  demux = gst_element_factory_make_or_warn ("dvdemux", "demuxer");
 -  v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
 -  decoder = gst_element_factory_make_or_warn ("ffdec_dvvideo", "decoder");
 -  videosink = gst_element_factory_make_or_warn (opt_videosink_str, "v_sink");
 -  a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
 -  audiosink = gst_element_factory_make_or_warn ("alsasink", "a_sink");
 -
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), demux);
 -  gst_bin_add (GST_BIN (pipeline), a_queue);
 -  gst_bin_add (GST_BIN (pipeline), audiosink);
 -  gst_bin_add (GST_BIN (pipeline), v_queue);
 -  gst_bin_add (GST_BIN (pipeline), decoder);
 -  gst_bin_add (GST_BIN (pipeline), videosink);
 -
 -  gst_element_link (src, demux);
 -  gst_element_link (a_queue, audiosink);
 -  gst_element_link (v_queue, decoder);
 -  gst_element_link (decoder, videosink);
 -
 -  setup_dynamic_link (demux, "video", gst_element_get_static_pad (v_queue,
 -          "sink"), NULL);
 -  setup_dynamic_link (demux, "audio", gst_element_get_static_pad (a_queue,
 -          "sink"), NULL);
 -
 -  seekable = gst_element_get_static_pad (decoder, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_wav_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline;
 -  GstElement *src, *decoder, *audiosink;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  decoder = gst_element_factory_make_or_warn ("wavparse", "decoder");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "sink");
 -
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), decoder);
 -  gst_bin_add (GST_BIN (pipeline), audiosink);
 -
 -  gst_element_link (src, decoder);
 -
 -  setup_dynamic_link (decoder, "src", gst_element_get_static_pad (audiosink,
 -          "sink"), NULL);
 -
 -  seekable_elements = g_list_prepend (seekable_elements, audiosink);
 -
 -  /* force element seeking on this pipeline */
 -  elem_seek = TRUE;
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_flac_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline;
 -  GstElement *src, *decoder, *audiosink;
 -  GstPad *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  decoder = gst_element_factory_make_or_warn ("flacdec", "decoder");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "sink");
 -  g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
 -
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), decoder);
 -  gst_bin_add (GST_BIN (pipeline), audiosink);
 -
 -  gst_element_link (src, decoder);
 -  gst_element_link (decoder, audiosink);
 -
 -  seekable = gst_element_get_static_pad (decoder, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_sid_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline;
 -  GstElement *src, *decoder, *audiosink;
 -  GstPad *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  decoder = gst_element_factory_make_or_warn ("siddec", "decoder");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "sink");
 -  //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
 -
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), decoder);
 -  gst_bin_add (GST_BIN (pipeline), audiosink);
 -
 -  gst_element_link (src, decoder);
 -  gst_element_link (decoder, audiosink);
 -
 -  seekable = gst_element_get_static_pad (decoder, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_parse_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline;
 -  GstElement *src, *parser, *fakesink;
 -  GstPad *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  parser = gst_element_factory_make_or_warn ("mpegparse", "parse");
 -  fakesink = gst_element_factory_make_or_warn ("fakesink", "sink");
 -  g_object_set (G_OBJECT (fakesink), "silent", TRUE, NULL);
 -  g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
 -
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), parser);
 -  gst_bin_add (GST_BIN (pipeline), fakesink);
 -
 -  gst_element_link (src, parser);
 -  gst_element_link (parser, fakesink);
 -
 -  seekable = gst_element_get_static_pad (parser, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (parser, "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_vorbis_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline, *audio_bin;
 -  GstElement *src, *demux, *decoder, *convert, *audiosink;
 -  GstPad *pad, *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
 -  decoder = gst_element_factory_make_or_warn ("vorbisdec", "decoder");
 -  convert = gst_element_factory_make_or_warn ("audioconvert", "convert");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "sink");
 -  g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
 -
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  audio_bin = gst_bin_new ("a_decoder_bin");
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), demux);
 -  gst_bin_add (GST_BIN (audio_bin), decoder);
 -  gst_bin_add (GST_BIN (audio_bin), convert);
 -  gst_bin_add (GST_BIN (audio_bin), audiosink);
 -  gst_bin_add (GST_BIN (pipeline), audio_bin);
 -
 -  gst_element_link (src, demux);
 -  gst_element_link (decoder, convert);
 -  gst_element_link (convert, audiosink);
 -
 -  pad = gst_element_get_static_pad (decoder, "sink");
 -  gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
 -  gst_object_unref (pad);
 -
 -  setup_dynamic_link (demux, NULL, gst_element_get_static_pad (audio_bin,
 -          "sink"), NULL);
 -
 -  seekable = gst_element_get_static_pad (decoder, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_theora_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline, *video_bin;
 -  GstElement *src, *demux, *decoder, *convert, *videosink;
 -  GstPad *pad, *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
 -  decoder = gst_element_factory_make_or_warn ("theoradec", "decoder");
 -  convert = gst_element_factory_make_or_warn ("ffmpegcolorspace", "convert");
 -  videosink = gst_element_factory_make_or_warn (opt_videosink_str, "sink");
 -
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  video_bin = gst_bin_new ("v_decoder_bin");
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), demux);
 -  gst_bin_add (GST_BIN (video_bin), decoder);
 -  gst_bin_add (GST_BIN (video_bin), convert);
 -  gst_bin_add (GST_BIN (video_bin), videosink);
 -  gst_bin_add (GST_BIN (pipeline), video_bin);
 -
 -  gst_element_link (src, demux);
 -  gst_element_link (decoder, convert);
 -  gst_element_link (convert, videosink);
 -
 -  pad = gst_element_get_static_pad (decoder, "sink");
 -  gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
 -  gst_object_unref (pad);
 -
 -  setup_dynamic_link (demux, NULL, gst_element_get_static_pad (video_bin,
 -          "sink"), NULL);
 -
 -  seekable = gst_element_get_static_pad (decoder, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_vorbis_theora_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline, *audio_bin, *video_bin;
 -  GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
 -  GstElement *audiosink, *videosink;
 -  GstElement *a_queue, *v_queue, *v_scale;
 -  GstPad *seekable;
 -  GstPad *pad;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), demux);
 -  gst_element_link (src, demux);
 -
 -  audio_bin = gst_bin_new ("a_decoder_bin");
 -  a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
 -  a_decoder = gst_element_factory_make_or_warn ("vorbisdec", "a_dec");
 -  a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "a_sink");
 -
 -  gst_bin_add (GST_BIN (pipeline), audio_bin);
 -
 -  gst_bin_add (GST_BIN (audio_bin), a_queue);
 -  gst_bin_add (GST_BIN (audio_bin), a_decoder);
 -  gst_bin_add (GST_BIN (audio_bin), a_convert);
 -  gst_bin_add (GST_BIN (audio_bin), audiosink);
 -
 -  gst_element_link (a_queue, a_decoder);
 -  gst_element_link (a_decoder, a_convert);
 -  gst_element_link (a_convert, audiosink);
 -
 -  pad = gst_element_get_static_pad (a_queue, "sink");
 -  gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
 -  gst_object_unref (pad);
 -
 -  setup_dynamic_link (demux, NULL, gst_element_get_static_pad (audio_bin,
 -          "sink"), NULL);
 -
 -  video_bin = gst_bin_new ("v_decoder_bin");
 -  v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
 -  v_decoder = gst_element_factory_make_or_warn ("theoradec", "v_dec");
 -  v_convert =
 -      gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
 -  v_scale = gst_element_factory_make_or_warn ("videoscale", "v_scale");
 -  videosink = gst_element_factory_make_or_warn (opt_videosink_str, "v_sink");
 -
 -  gst_bin_add (GST_BIN (pipeline), video_bin);
 -
 -  gst_bin_add (GST_BIN (video_bin), v_queue);
 -  gst_bin_add (GST_BIN (video_bin), v_decoder);
 -  gst_bin_add (GST_BIN (video_bin), v_convert);
 -  gst_bin_add (GST_BIN (video_bin), v_scale);
 -  gst_bin_add (GST_BIN (video_bin), videosink);
 -
 -  gst_element_link_many (v_queue, v_decoder, v_convert, v_scale, videosink,
 -      NULL);
 -
 -  pad = gst_element_get_static_pad (v_queue, "sink");
 -  gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
 -  gst_object_unref (pad);
 -
 -  setup_dynamic_link (demux, NULL, gst_element_get_static_pad (video_bin,
 -          "sink"), NULL);
 -
 -  seekable = gst_element_get_static_pad (a_decoder, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (a_decoder,
 -          "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_avi_msmpeg4v3_mp3_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline, *audio_bin, *video_bin;
 -  GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
 -  GstElement *audiosink, *videosink;
 -  GstElement *a_queue, *v_queue;
 -  GstPad *seekable, *pad;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  demux = gst_element_factory_make_or_warn ("avidemux", "demux");
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), demux);
 -  gst_element_link (src, demux);
 -
 -  audio_bin = gst_bin_new ("a_decoder_bin");
 -  a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
 -  a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
 -  a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "a_sink");
 -
 -  gst_bin_add (GST_BIN (audio_bin), a_queue);
 -  gst_bin_add (GST_BIN (audio_bin), a_decoder);
 -  gst_bin_add (GST_BIN (audio_bin), a_convert);
 -  gst_bin_add (GST_BIN (audio_bin), audiosink);
 -
 -  gst_element_link (a_queue, a_decoder);
 -  gst_element_link (a_decoder, a_convert);
 -  gst_element_link (a_convert, audiosink);
 -
 -  gst_bin_add (GST_BIN (pipeline), audio_bin);
 -
 -  pad = gst_element_get_static_pad (a_queue, "sink");
 -  gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
 -  gst_object_unref (pad);
 -
 -  setup_dynamic_link (demux, NULL, gst_element_get_static_pad (audio_bin,
 -          "sink"), NULL);
 -
 -  video_bin = gst_bin_new ("v_decoder_bin");
 -  v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
 -  v_decoder = gst_element_factory_make_or_warn ("ffdec_msmpeg4", "v_dec");
 -  v_convert =
 -      gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
 -  videosink = gst_element_factory_make_or_warn (opt_videosink_str, "v_sink");
 -
 -  gst_bin_add (GST_BIN (video_bin), v_queue);
 -  gst_bin_add (GST_BIN (video_bin), v_decoder);
 -  gst_bin_add (GST_BIN (video_bin), v_convert);
 -  gst_bin_add (GST_BIN (video_bin), videosink);
 -
 -  gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
 -
 -  gst_bin_add (GST_BIN (pipeline), video_bin);
 -
 -  pad = gst_element_get_static_pad (v_queue, "sink");
 -  gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
 -  gst_object_unref (pad);
 -
 -  setup_dynamic_link (demux, NULL, gst_element_get_static_pad (video_bin,
 -          "sink"), NULL);
 -
 -  seekable = gst_element_get_static_pad (a_decoder, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (a_decoder,
 -          "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_mp3_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline;
 -  GstElement *src, *parser, *decoder, *audiosink, *queue;
 -  GstPad *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  parser = gst_element_factory_make_or_warn ("mp3parse", "parse");
 -  decoder = gst_element_factory_make_or_warn ("mad", "dec");
 -  queue = gst_element_factory_make_or_warn ("queue", "queue");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "sink");
 -
 -  seekable_elements = g_list_prepend (seekable_elements, audiosink);
 -
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -  //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), parser);
 -  gst_bin_add (GST_BIN (pipeline), decoder);
 -  gst_bin_add (GST_BIN (pipeline), queue);
 -  gst_bin_add (GST_BIN (pipeline), audiosink);
 -
 -  gst_element_link (src, parser);
 -  gst_element_link (parser, decoder);
 -  gst_element_link (decoder, queue);
 -  gst_element_link (queue, audiosink);
 -
 -  seekable = gst_element_get_static_pad (queue, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_avi_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline, *audio_bin, *video_bin;
 -  GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
 -  GstElement *a_queue = NULL, *v_queue = NULL;
 -  GstPad *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  demux = gst_element_factory_make_or_warn ("avidemux", "demux");
 -  seekable_elements = g_list_prepend (seekable_elements, demux);
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), demux);
 -  gst_element_link (src, demux);
 -
 -  audio_bin = gst_bin_new ("a_decoder_bin");
 -  a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "a_sink");
 -  a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
 -  gst_element_link (a_decoder, a_queue);
 -  gst_element_link (a_queue, audiosink);
 -  gst_bin_add (GST_BIN (audio_bin), a_decoder);
 -  gst_bin_add (GST_BIN (audio_bin), a_queue);
 -  gst_bin_add (GST_BIN (audio_bin), audiosink);
 -  gst_element_set_state (audio_bin, GST_STATE_PAUSED);
 -
 -  setup_dynamic_link (demux, "audio_00", gst_element_get_static_pad (a_decoder,
 -          "sink"), audio_bin);
 -
 -  seekable = gst_element_get_static_pad (a_queue, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (a_decoder,
 -          "sink"));
 -
 -  video_bin = gst_bin_new ("v_decoder_bin");
 -  v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
 -  videosink = gst_element_factory_make_or_warn (opt_videosink_str, "v_sink");
 -  v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
 -  gst_element_link (v_decoder, v_queue);
 -  gst_element_link (v_queue, videosink);
 -  gst_bin_add (GST_BIN (video_bin), v_decoder);
 -  gst_bin_add (GST_BIN (video_bin), v_queue);
 -  gst_bin_add (GST_BIN (video_bin), videosink);
 -
 -  gst_element_set_state (video_bin, GST_STATE_PAUSED);
 -
 -  setup_dynamic_link (demux, "video_00", gst_element_get_static_pad (v_decoder,
 -          "sink"), video_bin);
 -
 -  seekable = gst_element_get_static_pad (v_queue, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (v_decoder,
 -          "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_mpeg_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline, *audio_bin, *video_bin;
 -  GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
 -  GstElement *audiosink, *videosink;
 -  GstElement *a_queue, *v_queue;
 -  GstPad *seekable;
 -  GstPad *pad;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  //demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
 -  demux = gst_element_factory_make_or_warn ("flupsdemux", "demux");
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), demux);
 -  gst_element_link (src, demux);
 -
 -  audio_bin = gst_bin_new ("a_decoder_bin");
 -  a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
 -  a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "a_sink");
 -  gst_bin_add (GST_BIN (audio_bin), a_decoder);
 -  gst_bin_add (GST_BIN (audio_bin), a_queue);
 -  gst_bin_add (GST_BIN (audio_bin), audiosink);
 -
 -  gst_element_link (a_decoder, a_queue);
 -  gst_element_link (a_queue, audiosink);
 -
 -  gst_bin_add (GST_BIN (pipeline), audio_bin);
 -
 -  pad = gst_element_get_static_pad (a_decoder, "sink");
 -  gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
 -  gst_object_unref (pad);
 -
 -  setup_dynamic_link (demux, "audio_c0", gst_element_get_static_pad (audio_bin,
 -          "sink"), NULL);
 -
 -  video_bin = gst_bin_new ("v_decoder_bin");
 -  v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
 -  v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
 -  v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
 -  videosink = gst_element_factory_make_or_warn (opt_videosink_str, "v_sink");
 -
 -  gst_bin_add (GST_BIN (video_bin), v_decoder);
 -  gst_bin_add (GST_BIN (video_bin), v_queue);
 -  gst_bin_add (GST_BIN (video_bin), v_filter);
 -  gst_bin_add (GST_BIN (video_bin), videosink);
 -
 -  gst_element_link (v_decoder, v_queue);
 -  gst_element_link (v_queue, v_filter);
 -  gst_element_link (v_filter, videosink);
 -
 -  gst_bin_add (GST_BIN (pipeline), video_bin);
 -
 -  pad = gst_element_get_static_pad (v_decoder, "sink");
 -  gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
 -  gst_object_unref (pad);
 -
 -  setup_dynamic_link (demux, "video_e0", gst_element_get_static_pad (video_bin,
 -          "sink"), NULL);
 -
 -  seekable = gst_element_get_static_pad (v_filter, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (v_decoder,
 -          "sink"));
 -
 -  return pipeline;
 -}
 -
 -static GstElement *
 -make_mpegnt_pipeline (const gchar * location)
 -{
 -  GstElement *pipeline, *audio_bin, *video_bin;
 -  GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
 -  GstElement *audiosink, *videosink;
 -  GstElement *a_queue;
 -  GstPad *seekable;
 -
 -  pipeline = gst_pipeline_new ("app");
 -
 -  src = gst_element_factory_make_or_warn (SOURCE, "src");
 -  g_object_set (G_OBJECT (src), "location", location, NULL);
 -
 -  demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
 -  //g_object_set (G_OBJECT (demux), "sync", TRUE, NULL);
 -
 -  seekable_elements = g_list_prepend (seekable_elements, demux);
 -
 -  gst_bin_add (GST_BIN (pipeline), src);
 -  gst_bin_add (GST_BIN (pipeline), demux);
 -  gst_element_link (src, demux);
 -
 -  audio_bin = gst_bin_new ("a_decoder_bin");
 -  a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
 -  a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
 -  audiosink = gst_element_factory_make_or_warn (opt_audiosink_str, "a_sink");
 -  //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
 -  g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
 -  gst_element_link (a_decoder, a_queue);
 -  gst_element_link (a_queue, audiosink);
 -  gst_bin_add (GST_BIN (audio_bin), a_decoder);
 -  gst_bin_add (GST_BIN (audio_bin), a_queue);
 -  gst_bin_add (GST_BIN (audio_bin), audiosink);
 -
 -  setup_dynamic_link (demux, "audio_00", gst_element_get_static_pad (a_decoder,
 -          "sink"), audio_bin);
 -
 -  seekable = gst_element_get_static_pad (a_queue, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (a_decoder,
 -          "sink"));
 -
 -  video_bin = gst_bin_new ("v_decoder_bin");
 -  v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
 -  v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
 -  videosink = gst_element_factory_make_or_warn (opt_videosink_str, "v_sink");
 -  gst_element_link_many (v_decoder, v_filter, videosink, NULL);
 -
 -  gst_bin_add_many (GST_BIN (video_bin), v_decoder, v_filter, videosink, NULL);
 -
 -  setup_dynamic_link (demux, "video_00", gst_element_get_static_pad (v_decoder,
 -          "sink"), video_bin);
 -
 -  seekable = gst_element_get_static_pad (v_decoder, "src");
 -  seekable_pads = g_list_prepend (seekable_pads, seekable);
 -  rate_pads = g_list_prepend (rate_pads, seekable);
 -  rate_pads =
 -      g_list_prepend (rate_pads, gst_element_get_static_pad (v_decoder,
 -          "sink"));
 -
 -  return pipeline;
 -}
 -
 -static void
  playerbin_set_uri (GstElement * player, const gchar * location)
  {
    gchar *uri;
  }
  
  static GstElement *
 -construct_playerbin (const gchar * name, const gchar * location)
 +construct_playbin (const gchar * name, const gchar * location)
  {
    GstElement *player;
    GstElement *avsink;
  
    seekable_elements = g_list_prepend (seekable_elements, player);
  
 -  /* force element seeking on this pipeline */
 -  elem_seek = TRUE;
 -
    avsink = gst_element_factory_make_or_warn (opt_audiosink_str, "a_sink");
    if (avsink)
      g_object_set (player, "audio-sink", avsink, NULL);
  }
  
  static GstElement *
 -make_playerbin_pipeline (const gchar * location)
 -{
 -  return construct_playerbin ("playbin", location);
 -}
 -
 -static GstElement *
 -make_playerbin2_pipeline (const gchar * location)
 +make_playbin_pipeline (const gchar * location)
  {
 -  GstElement *pipeline = construct_playerbin ("playbin2", location);
 +  GstElement *pipeline = construct_playbin ("playbin", location);
  
 -  /* FIXME: this is not triggered, playbin2 is not forwarding it from the sink */
 +  /* FIXME: this is not triggered, playbin is not forwarding it from the sink */
    g_signal_connect (pipeline, "notify::volume", G_CALLBACK (volume_notify_cb),
        NULL);
    return pipeline;
@@@ -231,6 -991,8 +241,6 @@@ make_parselaunch_pipeline (const gchar 
  
    seekable_elements = g_list_prepend (seekable_elements, pipeline);
  
 -  elem_seek = TRUE;
 -
    return pipeline;
  }
  #endif
@@@ -243,10 -1005,25 +253,10 @@@ typedef struc
  Pipeline;
  
  static Pipeline pipelines[] = {
 -  {"mp3", make_mp3_pipeline},
 -  {"avi", make_avi_pipeline},
 -  {"mpeg1", make_mpeg_pipeline},
 -  {"mpegparse", make_parse_pipeline},
 -  {"vorbis", make_vorbis_pipeline},
 -  {"theora", make_theora_pipeline},
 -  {"ogg/v/t", make_vorbis_theora_pipeline},
 -  {"avi/msmpeg4v3/mp3", make_avi_msmpeg4v3_mp3_pipeline},
 -  {"sid", make_sid_pipeline},
 -  {"flac", make_flac_pipeline},
 -  {"wav", make_wav_pipeline},
 -  {"mod", make_mod_pipeline},
 -  {"dv", make_dv_pipeline},
 -  {"mpeg1nothreads", make_mpegnt_pipeline},
 -  {"playerbin", make_playerbin_pipeline},
 +  {"playbin", make_playbin_pipeline},
  #ifndef GST_DISABLE_PARSE
    {"parse-launch", make_parselaunch_pipeline},
  #endif
 -  {"playerbin2", make_playerbin2_pipeline},
    {NULL, NULL},
  };
  
@@@ -292,6 -1069,37 +302,6 @@@ static seek_format seek_formats[] = 
  };
  
  G_GNUC_UNUSED static void
 -query_rates (void)
 -{
 -  GList *walk = rate_pads;
 -
 -  while (walk) {
 -    GstPad *pad = GST_PAD (walk->data);
 -    gint i = 0;
 -
 -    g_print ("rate/sec  %8.8s: ", GST_PAD_NAME (pad));
 -    while (seek_formats[i].name) {
 -      gint64 value;
 -      GstFormat format;
 -
 -      format = seek_formats[i].format;
 -
 -      if (gst_pad_query_convert (pad, GST_FORMAT_TIME, GST_SECOND, &format,
 -              &value)) {
 -        g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
 -      } else {
 -        g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
 -      }
 -
 -      i++;
 -    }
 -    g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
 -
 -    walk = g_list_next (walk);
 -  }
 -}
 -
 -G_GNUC_UNUSED static void
  query_positions_elems (void)
  {
    GList *walk = seekable_elements;
  
        format = seek_formats[i].format;
  
 -      if (gst_element_query_position (element, &format, &position) &&
 -          gst_element_query_duration (element, &format, &total)) {
 +      if (gst_element_query_position (element, format, &position) &&
 +          gst_element_query_duration (element, format, &total)) {
          g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
              seek_formats[i].name, position, total);
        } else {
    }
  }
  
 -G_GNUC_UNUSED static void
 -query_positions_pads (void)
 -{
 -  GList *walk = seekable_pads;
 -
 -  while (walk) {
 -    GstPad *pad = GST_PAD (walk->data);
 -    gint i = 0;
 -
 -    g_print ("positions %8.8s: ", GST_PAD_NAME (pad));
 -    while (seek_formats[i].name) {
 -      GstFormat format;
 -      gint64 position, total;
 -
 -      format = seek_formats[i].format;
 -
 -      if (gst_pad_query_position (pad, &format, &position) &&
 -          gst_pad_query_duration (pad, &format, &total)) {
 -        g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
 -            seek_formats[i].name, position, total);
 -      } else {
 -        g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
 -            "*NA*");
 -      }
 -
 -      i++;
 -    }
 -    g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
 -
 -    walk = g_list_next (walk);
 -  }
 -}
 -
  static gboolean start_seek (GtkWidget * widget, GdkEventButton * event,
      gpointer user_data);
  static gboolean stop_seek (GtkWidget * widget, GdkEventButton * event,
@@@ -350,42 -1191,44 +360,42 @@@ set_scale (gdouble value
  static gboolean
  update_fill (gpointer data)
  {
 -  if (elem_seek) {
 -    if (seekable_elements) {
 -      GstElement *element = GST_ELEMENT (seekable_elements->data);
 -      GstQuery *query;
 -
 -      query = gst_query_new_buffering (GST_FORMAT_PERCENT);
 -      if (gst_element_query (element, query)) {
 -        gint64 start, stop, buffering_total;
 -        GstFormat format;
 -        gdouble fill;
 -        gboolean busy;
 -        gint percent;
 -        GstBufferingMode mode;
 -        gint avg_in, avg_out;
 -        gint64 buffering_left;
 -
 -        gst_query_parse_buffering_percent (query, &busy, &percent);
 -        gst_query_parse_buffering_range (query, &format, &start, &stop,
 -            &buffering_total);
 -        gst_query_parse_buffering_stats (query, &mode, &avg_in, &avg_out,
 -            &buffering_left);
 -
 -        /* note that we could start the playback when buffering_left < remaining
 -         * playback time */
 -        GST_DEBUG ("buffering total %" G_GINT64_FORMAT " ms, left %"
 -            G_GINT64_FORMAT " ms", buffering_total, buffering_left);
 -        GST_DEBUG ("start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT,
 -            start, stop);
 -
 -        if (stop != -1)
 -          fill = N_GRAD * stop / GST_FORMAT_PERCENT_MAX;
 -        else
 -          fill = N_GRAD;
 -
 -        gtk_range_set_fill_level (GTK_RANGE (hscale), fill);
 -      }
 -      gst_query_unref (query);
 +  if (seekable_elements) {
 +    GstElement *element = GST_ELEMENT (seekable_elements->data);
 +    GstQuery *query;
 +
 +    query = gst_query_new_buffering (GST_FORMAT_PERCENT);
 +    if (gst_element_query (element, query)) {
 +      gint64 start, stop, buffering_total;
 +      GstFormat format;
 +      gdouble fill;
 +      gboolean busy;
 +      gint percent;
 +      GstBufferingMode mode;
 +      gint avg_in, avg_out;
 +      gint64 buffering_left;
 +
 +      gst_query_parse_buffering_percent (query, &busy, &percent);
 +      gst_query_parse_buffering_range (query, &format, &start, &stop,
 +          &buffering_total);
 +      gst_query_parse_buffering_stats (query, &mode, &avg_in, &avg_out,
 +          &buffering_left);
 +
 +      /* note that we could start the playback when buffering_left < remaining
 +       * playback time */
 +      GST_DEBUG ("buffering total %" G_GINT64_FORMAT " ms, left %"
 +          G_GINT64_FORMAT " ms", buffering_total, buffering_left);
 +      GST_DEBUG ("start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT,
 +          start, stop);
 +
 +      if (stop != -1)
 +        fill = N_GRAD * stop / GST_FORMAT_PERCENT_MAX;
 +      else
 +        fill = N_GRAD;
 +
 +      gtk_range_set_fill_level (GTK_RANGE (hscale), fill);
      }
 +    gst_query_unref (query);
    }
    return TRUE;
  }
  static gboolean
  update_scale (gpointer data)
  {
 -  GstFormat format = GST_FORMAT_TIME;
 -
 -  //position = 0;
 -  //duration = 0;
 +  if (seekable_elements) {
 +    GstElement *element = GST_ELEMENT (seekable_elements->data);
  
 -  if (elem_seek) {
 -    if (seekable_elements) {
 -      GstElement *element = GST_ELEMENT (seekable_elements->data);
 -
 -      gst_element_query_position (element, &format, &position);
 -      gst_element_query_duration (element, &format, &duration);
 -    }
 -  } else {
 -    if (seekable_pads) {
 -      GstPad *pad = GST_PAD (seekable_pads->data);
 -
 -      gst_pad_query_position (pad, &format, &position);
 -      gst_pad_query_duration (pad, &format, &duration);
 -    }
 +    gst_element_query_position (element, GST_FORMAT_TIME, &position);
 +    gst_element_query_duration (element, GST_FORMAT_TIME, &duration);
    }
  
    if (stats) {
 -    if (elem_seek) {
 -      query_positions_elems ();
 -    } else {
 -      query_positions_pads ();
 -    }
 -    query_rates ();
 +    query_positions_elems ();
    }
  
    if (position >= duration)
@@@ -438,17 -1300,33 +448,17 @@@ static gboolea
  send_event (GstEvent * event)
  {
    gboolean res = FALSE;
 +  GList *walk = seekable_elements;
  
 -  if (!elem_seek) {
 -    GList *walk = seekable_pads;
 -
 -    while (walk) {
 -      GstPad *seekable = GST_PAD (walk->data);
 -
 -      GST_DEBUG ("send event on pad %s:%s", GST_DEBUG_PAD_NAME (seekable));
 -
 -      gst_event_ref (event);
 -      res = gst_pad_send_event (seekable, event);
 -
 -      walk = g_list_next (walk);
 -    }
 -  } else {
 -    GList *walk = seekable_elements;
 -
 -    while (walk) {
 -      GstElement *seekable = GST_ELEMENT (walk->data);
 +  while (walk) {
 +    GstElement *seekable = GST_ELEMENT (walk->data);
  
 -      GST_DEBUG ("send event on element %s", GST_ELEMENT_NAME (seekable));
 +    GST_DEBUG ("send event on element %s", GST_ELEMENT_NAME (seekable));
  
 -      gst_event_ref (event);
 -      res = gst_element_send_event (seekable, event);
 +    gst_event_ref (event);
 +    res = gst_element_send_event (seekable, event);
  
 -      walk = g_list_next (walk);
 -    }
 +    walk = g_list_next (walk);
    }
    gst_event_unref (event);
    return res;
@@@ -725,6 -1603,10 +735,6 @@@ stop_cb (GtkButton * button, gpointer d
  
        g_list_free (seekable_elements);
        seekable_elements = NULL;
 -      g_list_free (seekable_pads);
 -      seekable_pads = NULL;
 -      g_list_free (rate_pads);
 -      rate_pads = NULL;
  
        pipeline = pipelines[pipeline_type].func (pipeline_spec);
        g_assert (pipeline);
@@@ -1130,9 -2012,6 +1140,9 @@@ volume_notify_cb (GstElement * pipeline
  {
    gdouble cur_volume, new_volume;
  
 +  if (volume_spinbutton == NULL)
 +    return;
 +
    g_object_get (pipeline, "volume", &new_volume, NULL);
    cur_volume = gtk_spin_button_get_value (GTK_SPIN_BUTTON (volume_spinbutton));
    if (fabs (cur_volume - new_volume) > 0.001) {
@@@ -1173,18 -2052,12 +1183,18 @@@ shot_cb (GtkButton * button, gpointer d
      gint width, height;
      GdkPixbuf *pixbuf;
      GError *error = NULL;
 +    guint8 *data;
 +    gsize size;
  
      /* get the snapshot buffer format now. We set the caps on the appsink so
       * that it can only be an rgb buffer. The only thing we have not specified
       * on the caps is the height, which is dependant on the pixel-aspect-ratio
       * of the source material */
 +#if 0
      caps = GST_BUFFER_CAPS (buffer);
 +#endif
 +    /* FIXME, need to get the caps of the buffer somehow */
 +    caps = NULL;
      if (!caps) {
        g_warning ("could not get snapshot format\n");
        goto done;
  
      /* create pixmap from buffer and save, gstreamer video buffers have a stride
       * that is rounded up to the nearest multiple of 4 */
 -    pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer),
 +    data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
 +    pixbuf = gdk_pixbuf_new_from_data (data,
          GDK_COLORSPACE_RGB, FALSE, 8, width, height,
          GST_ROUND_UP_4 (width * 3), NULL, NULL);
  
      /* save the pixbuf */
      gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
 +    gst_buffer_unmap (buffer, data, size);
  
    done:
      gst_buffer_unref (buffer);
@@@ -1575,7 -2446,7 +1585,7 @@@ msg_clock_lost (GstBus * bus, GstMessag
  
  static gulong embed_xid = 0;
  
 -/* We set the xid here in response to the prepare-xwindow-id message via a
 +/* We set the xid here in response to the prepare-window-handle 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
  static GstBusSyncReply
  bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data)
  {
 -  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));
 +  GstElement *element;
  
 -    g_print ("got prepare-xwindow-id, setting XID %lu\n", embed_xid);
 +  if (!gst_is_video_overlay_prepare_window_handle_message (message))
 +    return GST_BUS_PASS;
  
 -    if (g_object_class_find_property (G_OBJECT_GET_CLASS (element),
 -            "force-aspect-ratio")) {
 -      g_object_set (element, "force-aspect-ratio", TRUE, NULL);
 -    }
 +  element = GST_ELEMENT (GST_MESSAGE_SRC (message));
  
 -    /* 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);
 +  g_print ("got prepare-window-handle, setting XID %lu\n", embed_xid);
  
 -    gst_x_overlay_set_window_handle (GST_X_OVERLAY (element), 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);
    }
 +
 +  /* 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_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (element), embed_xid);
    return GST_BUS_PASS;
  }
  #endif
@@@ -1637,7 -2506,7 +1647,7 @@@ realize_cb (GtkWidget * widget, gpointe
      /* This is here just for pedagogical purposes, GDK_WINDOW_XID will call it
       * as well */
      if (!gdk_window_ensure_native (window))
 -      g_error ("Couldn't create native window needed for GstXOverlay!");
 +      g_error ("Couldn't create native window needed for GstVideoOverlay!");
    }
  #endif
  
@@@ -1684,7 -2553,7 +1694,7 @@@ connect_bus_signals (GstElement * pipel
    GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  
  #if defined (GDK_WINDOWING_X11) || defined (GDK_WINDOWING_WIN32)
 -  /* handle prepare-xwindow-id element message synchronously */
 +  /* handle prepare-window-handle element message synchronously */
    gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler,
        pipeline);
  #endif
@@@ -1794,6 -2663,8 +1804,6 @@@ main (int argc, char **argv
          "audio sink to use (default: " DEFAULT_AUDIOSINK ")", NULL},
      {"stats", 's', 0, G_OPTION_ARG_NONE, &stats,
          "Show pad stats", NULL},
 -    {"elem", 'e', 0, G_OPTION_ARG_NONE, &elem_seek,
 -        "Seek on elements instead of pads", NULL},
      {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
          "Verbose properties", NULL},
      {"videosink", '\0', 0, G_OPTION_ARG_STRING, &opt_videosink_str,
    g_signal_connect (hscale, "format_value", G_CALLBACK (format_value),
        pipeline);
  
 -  if (pipeline_type == 16) {
 +  if (pipeline_type == 0) {
      /* the playbin2 panel controls for the video/audio/subtitle tracks */
      panel = gtk_hbox_new (FALSE, 0);
      video_combo = gtk_combo_box_text_new ();
@@@ -1,5 -1,5 +1,5 @@@
  EXPORTS
-       _gst_base_audio_decoder_error
+       _gst_audio_decoder_error
        gst_audio_buffer_clip
        gst_audio_channel_position_get_type
        gst_audio_check_channel_positions
        gst_audio_clock_new
        gst_audio_clock_new_full
        gst_audio_clock_reset
+       gst_audio_decoder_finish_frame
+       gst_audio_decoder_get_audio_info
+       gst_audio_decoder_get_byte_time
+       gst_audio_decoder_get_delay
+       gst_audio_decoder_get_latency
+       gst_audio_decoder_get_max_errors
+       gst_audio_decoder_get_min_latency
+       gst_audio_decoder_get_parse_state
+       gst_audio_decoder_get_plc
+       gst_audio_decoder_get_plc_aware
+       gst_audio_decoder_get_tolerance
+       gst_audio_decoder_get_type
+       gst_audio_decoder_set_byte_time
+       gst_audio_decoder_set_latency
+       gst_audio_decoder_set_max_errors
+       gst_audio_decoder_set_min_latency
+       gst_audio_decoder_set_plc
+       gst_audio_decoder_set_plc_aware
+       gst_audio_decoder_set_tolerance
        gst_audio_default_registry_mixer_filter
+       gst_audio_duration_from_pad_buffer
+       gst_audio_encoder_finish_frame
+       gst_audio_encoder_get_audio_info
+       gst_audio_encoder_get_frame_max
+       gst_audio_encoder_get_frame_samples
+       gst_audio_encoder_get_hard_resync
+       gst_audio_encoder_get_latency
+       gst_audio_encoder_get_lookahead
+       gst_audio_encoder_get_mark_granule
+       gst_audio_encoder_get_perfect_timestamp
+       gst_audio_encoder_get_tolerance
+       gst_audio_encoder_get_type
+       gst_audio_encoder_proxy_getcaps
+       gst_audio_encoder_set_frame_max
+       gst_audio_encoder_set_frame_samples
+       gst_audio_encoder_set_hard_resync
+       gst_audio_encoder_set_latency
+       gst_audio_encoder_set_lookahead
+       gst_audio_encoder_set_mark_granule
+       gst_audio_encoder_set_perfect_timestamp
+       gst_audio_encoder_set_tolerance
        gst_audio_filter_class_add_pad_templates
        gst_audio_filter_get_type
        gst_audio_fixate_channel_positions
 -      gst_audio_frame_byte_size
 -      gst_audio_frame_length
 +      gst_audio_format_build_integer
 +      gst_audio_format_fill_silence
 +      gst_audio_format_from_string
 +      gst_audio_format_get_info
 +      gst_audio_format_to_string
        gst_audio_get_channel_positions
        gst_audio_iec61937_frame_size
        gst_audio_iec61937_payload
 -      gst_audio_info_clear
        gst_audio_info_convert
 -      gst_audio_info_copy
 -      gst_audio_info_free
        gst_audio_info_from_caps
        gst_audio_info_init
 +      gst_audio_info_set_format
        gst_audio_info_to_caps
 -      gst_audio_is_buffer_framed
        gst_audio_set_caps_channel_positions_list
        gst_audio_set_channel_positions
        gst_audio_set_structure_channel_positions_list
        gst_audio_sink_get_type
        gst_audio_src_get_type
        gst_audio_structure_set_int
-       gst_base_audio_decoder_finish_frame
-       gst_base_audio_decoder_get_audio_info
-       gst_base_audio_decoder_get_byte_time
-       gst_base_audio_decoder_get_delay
-       gst_base_audio_decoder_get_latency
-       gst_base_audio_decoder_get_max_errors
-       gst_base_audio_decoder_get_min_latency
-       gst_base_audio_decoder_get_parse_state
-       gst_base_audio_decoder_get_plc
-       gst_base_audio_decoder_get_plc_aware
-       gst_base_audio_decoder_get_tolerance
-       gst_base_audio_decoder_get_type
-       gst_base_audio_decoder_set_byte_time
-       gst_base_audio_decoder_set_latency
-       gst_base_audio_decoder_set_max_errors
-       gst_base_audio_decoder_set_min_latency
-       gst_base_audio_decoder_set_plc
-       gst_base_audio_decoder_set_plc_aware
-       gst_base_audio_decoder_set_tolerance
-       gst_base_audio_encoder_finish_frame
-       gst_base_audio_encoder_get_audio_info
-       gst_base_audio_encoder_get_frame_max
-       gst_base_audio_encoder_get_frame_samples
-       gst_base_audio_encoder_get_hard_resync
-       gst_base_audio_encoder_get_latency
-       gst_base_audio_encoder_get_lookahead
-       gst_base_audio_encoder_get_mark_granule
-       gst_base_audio_encoder_get_perfect_timestamp
-       gst_base_audio_encoder_get_tolerance
-       gst_base_audio_encoder_get_type
-       gst_base_audio_encoder_proxy_getcaps
-       gst_base_audio_encoder_set_frame_max
-       gst_base_audio_encoder_set_frame_samples
-       gst_base_audio_encoder_set_hard_resync
-       gst_base_audio_encoder_set_latency
-       gst_base_audio_encoder_set_lookahead
-       gst_base_audio_encoder_set_mark_granule
-       gst_base_audio_encoder_set_perfect_timestamp
-       gst_base_audio_encoder_set_tolerance
- >>>>>>> master
        gst_base_audio_sink_create_ringbuffer
        gst_base_audio_sink_get_drift_tolerance
        gst_base_audio_sink_get_provide_clock
@@@ -89,6 -89,7 +89,6 @@@
        gst_base_audio_src_set_provide_clock
        gst_base_audio_src_set_slave_method
        gst_base_audio_src_slave_method_get_type
 -      gst_buffer_format_get_type
        gst_buffer_format_type_get_type
        gst_ring_buffer_acquire
        gst_ring_buffer_activate