Merge branch 'master' into 0.11
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 24 May 2011 15:34:19 +0000 (17:34 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 24 May 2011 15:34:19 +0000 (17:34 +0200)
Conflicts:
gst/avi/gstavidemux.c
gst/rtp/gstrtpac3depay.c
gst/rtp/gstrtpg726depay.c
gst/rtp/gstrtpmpvdepay.c
gst/videofilter/gstgamma.c

43 files changed:
common
configure.ac
docs/plugins/gst-plugins-good-plugins.args
docs/plugins/gst-plugins-good-plugins.hierarchy
docs/plugins/gst-plugins-good-plugins.interfaces
docs/plugins/gst-plugins-good-plugins.prerequisites
ext/flac/gstflacdec.c
gst/audioparsers/gstflacparse.c
gst/auparse/gstauparse.c
gst/avi/gstavidemux.c
gst/debugutils/rndbuffersize.c
gst/deinterlace/gstdeinterlace.c
gst/deinterlace/gstdeinterlace.h
gst/isomp4/qtdemux.c
gst/matroska/Makefile.am
gst/matroska/matroska-demux.c
gst/matroska/matroska-demux.h
gst/matroska/matroska-parse.c
gst/matroska/matroska-parse.h
gst/matroska/matroska-read-common.c [new file with mode: 0644]
gst/matroska/matroska-read-common.h [new file with mode: 0644]
gst/rtp/gstrtpac3depay.c
gst/rtp/gstrtpbvdepay.c
gst/rtp/gstrtpg722depay.c
gst/rtp/gstrtpg726depay.c
gst/rtp/gstrtpgsmdepay.c
gst/rtp/gstrtpilbcdepay.c
gst/rtp/gstrtpjpegpay.c
gst/rtp/gstrtpmp1sdepay.c
gst/rtp/gstrtpmp2tdepay.c
gst/rtp/gstrtpmp4adepay.c
gst/rtp/gstrtpmpvdepay.c
gst/rtp/gstrtppcmadepay.c
gst/rtp/gstrtppcmudepay.c
gst/rtp/gstrtpqcelpdepay.c
gst/rtp/gstrtpspeexdepay.c
gst/rtsp/gstrtspsrc.c
sys/v4l2/gstv4l2object.c
sys/v4l2/gstv4l2object.h
sys/v4l2/gstv4l2sink.c
sys/v4l2/gstv4l2tuner.c
sys/v4l2/gstv4l2tuner.h
sys/v4l2/v4l2_calls.c

diff --git a/common b/common
index 46dfcea..69b981f 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 46dfcea233cf6df83e3771d8a8066e87d614f893
+Subproject commit 69b981f10caa234ad0ff639179d0fda8505bd94b
index 09b435c..77cfe51 100644 (file)
@@ -813,15 +813,6 @@ dnl *** libcaca ***
 translit(dnm, m, l) AM_CONDITIONAL(USE_LIBCACA, true)
 AG_GST_CHECK_FEATURE(LIBCACA, [libcaca coloured ASCII art], cacasink, [
   AG_GST_PKG_CHECK_MODULES(LIBCACA, caca)
-  dnl only newer versions of libcaca ship caca.pc, so try caca-config as well
-  if test "x$HAVE_LIBCACA" != "xyes"; then
-    AG_GST_CHECK_CONFIGPROG(LIBCACA, caca-config)
-    dnl see if it compilation works too, might not if we are cross-compiling
-    if test "x$HAVE_LIBCACA" = "xyes"; then
-      AC_CHECK_LIB([caca], [caca_init], [HAVE_LIBCACA=yes],
-                   [HAVE_LIBCACA=no], [$LIBCACA_LIBS])
-    fi
-  fi
 ])
 
 dnl *** libdv ***
index acbd788..0c96249 100644 (file)
 <ARG>
 <NAME>GstUDPSrc::sockfd</NAME>
 <TYPE>gint</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Socket Handle</NICK>
 <BLURB>Socket to use for UDP reception. (-1 == allocate).</BLURB>
 <ARG>
 <NAME>GstUDPSrc::sock</NAME>
 <TYPE>gint</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>r</FLAGS>
 <NICK>Socket Handle</NICK>
 <BLURB>Socket currently in use for UDP reception. (-1 = no socket).</BLURB>
 <ARG>
 <NAME>GstDV1394Src::port</NAME>
 <TYPE>gint</TYPE>
-<RANGE>[G_MAXULONG,16]</RANGE>
+<RANGE>[-1,16]</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Port</NICK>
 <BLURB>Port number (-1 automatic).</BLURB>
 <ARG>
 <NAME>GstTest::allowed-timestamp-deviation</NAME>
 <TYPE>gint64</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>rwx</FLAGS>
 <NICK>allowed timestamp deviation</NICK>
 <BLURB>allowed average difference in usec between timestamp of next buffer and expected timestamp from analyzing last buffer.</BLURB>
 <ARG>
 <NAME>GstTest::buffer-count</NAME>
 <TYPE>gint64</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>r</FLAGS>
 <NICK>buffer count</NICK>
 <BLURB>number of buffers in stream.</BLURB>
 <ARG>
 <NAME>GstTest::expected-buffer-count</NAME>
 <TYPE>gint64</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>rwx</FLAGS>
 <NICK>expected buffer count</NICK>
 <BLURB>expected number of buffers in stream.</BLURB>
 <ARG>
 <NAME>GstTest::expected-length</NAME>
 <TYPE>gint64</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>rwx</FLAGS>
 <NICK>expected length</NICK>
 <BLURB>expected length of stream.</BLURB>
 <ARG>
 <NAME>GstTest::length</NAME>
 <TYPE>gint64</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>r</FLAGS>
 <NICK>length</NICK>
 <BLURB>length of stream.</BLURB>
 <ARG>
 <NAME>GstTest::timestamp-deviation</NAME>
 <TYPE>gint64</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>r</FLAGS>
 <NICK>timestamp deviation</NICK>
 <BLURB>average difference in usec between timestamp of next buffer and expected timestamp from analyzing last buffer.</BLURB>
 <ARG>
 <NAME>GstBreakMyData::set-to</NAME>
 <TYPE>gint</TYPE>
-<RANGE>[G_MAXULONG,255]</RANGE>
+<RANGE>[-1,255]</RANGE>
 <FLAGS>rwx</FLAGS>
 <NICK>set-to</NICK>
 <BLURB>set changed bytes to this value (-1 means random value.</BLURB>
 <ARG>
 <NAME>GstDynUDPSink::sockfd</NAME>
 <TYPE>gint</TYPE>
-<RANGE>[G_MAXULONG,32767]</RANGE>
+<RANGE>[-1,32767]</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>socket handle</NICK>
 <BLURB>Socket to use for UDP sending. (-1 == allocate).</BLURB>
 <ARG>
 <NAME>GstMultiUDPSink::sock</NAME>
 <TYPE>gint</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>r</FLAGS>
 <NICK>Socket Handle</NICK>
 <BLURB>Socket currently in use for UDP sending. (-1 == no socket).</BLURB>
 <ARG>
 <NAME>GstMultiUDPSink::sockfd</NAME>
 <TYPE>gint</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Socket Handle</NICK>
 <BLURB>Socket to use for UDP sending. (-1 == allocate).</BLURB>
 <ARG>
 <NAME>GstMultiUDPSink::qos-dscp</NAME>
 <TYPE>gint</TYPE>
-<RANGE>[G_MAXULONG,63]</RANGE>
+<RANGE>[-1,63]</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>QoS diff srv code point</NICK>
 <BLURB>Quality of Service, differentiated services code point (-1 default).</BLURB>
 <ARG>
 <NAME>GstXImageSrc::screen-num</NAME>
 <TYPE>guint</TYPE>
-<RANGE><= G_MAXINT</RANGE>
+<RANGE><= G_MAXLONG</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Screen number</NICK>
 <BLURB>X Screen Number.</BLURB>
 <ARG>
 <NAME>GstXImageSrc::endx</NAME>
 <TYPE>guint</TYPE>
-<RANGE><= G_MAXINT</RANGE>
+<RANGE><= G_MAXLONG</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>End X</NICK>
 <BLURB>X coordinate of bottom right corner of area to be recorded (0 for bottom right of screen).</BLURB>
 <ARG>
 <NAME>GstXImageSrc::endy</NAME>
 <TYPE>guint</TYPE>
-<RANGE><= G_MAXINT</RANGE>
+<RANGE><= G_MAXLONG</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>End Y</NICK>
 <BLURB>Y coordinate of bottom right corner of area to be recorded (0 for bottom right of screen).</BLURB>
 <ARG>
 <NAME>GstXImageSrc::startx</NAME>
 <TYPE>guint</TYPE>
-<RANGE><= G_MAXINT</RANGE>
+<RANGE><= G_MAXLONG</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Start X co-ordinate</NICK>
 <BLURB>X coordinate of top left corner of area to be recorded (0 for top left of screen).</BLURB>
 <ARG>
 <NAME>GstXImageSrc::starty</NAME>
 <TYPE>guint</TYPE>
-<RANGE><= G_MAXINT</RANGE>
+<RANGE><= G_MAXLONG</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Start Y co-ordinate</NICK>
 <BLURB>Y coordinate of top left corner of area to be recorded (0 for top left of screen).</BLURB>
 <ARG>
 <NAME>GstJpegDec::max-errors</NAME>
 <TYPE>gint</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Maximum Consecutive Decoding Errors</NICK>
 <BLURB>Error out after receiving N consecutive decoding errors (-1 = never fail, 0 = automatic, 1 = fail on first error).</BLURB>
 <ARG>
 <NAME>GstV4l2Src::device-fd</NAME>
 <TYPE>gint</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>r</FLAGS>
 <NICK>File descriptor</NICK>
 <BLURB>File descriptor of the device.</BLURB>
 <ARG>
 <NAME>GstRndBufferSize::max</NAME>
 <TYPE>glong</TYPE>
-<RANGE>[1,G_MAXINT]</RANGE>
+<RANGE>>= 1</RANGE>
 <FLAGS>rwx</FLAGS>
 <NICK>maximum</NICK>
 <BLURB>maximum buffer size.</BLURB>
 <ARG>
 <NAME>GstRndBufferSize::min</NAME>
 <TYPE>glong</TYPE>
-<RANGE>[0,G_MAXINT]</RANGE>
+<RANGE>>= 0</RANGE>
 <FLAGS>rwx</FLAGS>
 <NICK>mininum</NICK>
 <BLURB>mininum buffer size.</BLURB>
 <ARG>
 <NAME>GstRndBufferSize::seed</NAME>
 <TYPE>gulong</TYPE>
-<RANGE><= G_MAXUINT</RANGE>
+<RANGE></RANGE>
 <FLAGS>rwx</FLAGS>
 <NICK>random number seed</NICK>
 <BLURB>seed for randomness (initialized when going from READY to PAUSED).</BLURB>
 <ARG>
 <NAME>GstHDV1394Src::port</NAME>
 <TYPE>gint</TYPE>
-<RANGE>[G_MAXULONG,16]</RANGE>
+<RANGE>[-1,16]</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Port</NICK>
 <BLURB>Port number (-1 automatic).</BLURB>
 </ARG>
 
 <ARG>
+<NAME>GstDeinterlace::drop-orphans</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>drop-orphans</NICK>
+<BLURB>Drop orphan fields at the beginning of telecine patterns in active locking mode.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDeinterlace::ignore-obscure</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>ignore-obscure</NICK>
+<BLURB>Ignore obscure telecine patterns (only consider P, I and 2:3 variants).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDeinterlace::locking</NAME>
+<TYPE>GstDeinterlaceLocking</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>locking</NICK>
+<BLURB>Pattern locking mode.</BLURB>
+<DEFAULT>No pattern locking</DEFAULT>
+</ARG>
+
+<ARG>
 <NAME>GstAgingTV::color-aging</NAME>
 <TYPE>gboolean</TYPE>
 <RANGE></RANGE>
 <ARG>
 <NAME>GstOpTV::threshold</NAME>
 <TYPE>guint</TYPE>
-<RANGE><= G_MAXINT</RANGE>
+<RANGE><= G_MAXLONG</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Threshold</NICK>
 <BLURB>Luma threshold.</BLURB>
 <ARG>
 <NAME>GstRadioacTV::interval</NAME>
 <TYPE>guint</TYPE>
-<RANGE><= G_MAXINT</RANGE>
+<RANGE><= G_MAXLONG</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>Interval</NICK>
 <BLURB>Snapshot interval (in strobe mode).</BLURB>
 <ARG>
 <NAME>GstRtpSession::rtcp-rr-bandwidth</NAME>
 <TYPE>gint</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>RTCP RR bandwidth</NICK>
 <BLURB>The RTCP bandwidth used for receivers in bytes per second (-1 = default).</BLURB>
 <ARG>
 <NAME>GstRtpSession::rtcp-rs-bandwidth</NAME>
 <TYPE>gint</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>rw</FLAGS>
 <NICK>RTCP RS bandwidth</NICK>
 <BLURB>The RTCP bandwidth used for senders in bytes per second (-1 = default).</BLURB>
 <ARG>
 <NAME>GstV4l2Sink::device-fd</NAME>
 <TYPE>gint</TYPE>
-<RANGE>>= G_MAXULONG</RANGE>
+<RANGE>>= -1</RANGE>
 <FLAGS>r</FLAGS>
 <NICK>File descriptor</NICK>
 <BLURB>File descriptor of the device.</BLURB>
index 33aceea..5e1dff3 100644 (file)
 GObject
+  GdkPixbuf
+  GstCmmlTagClip
+  GstCmmlTagHead
+  GstCmmlTagStream
+  GstColorBalanceChannel
   GstObject
-    GstPad
-      GstVideoMixer2Pad
-      GstVideoMixerPad
-      GstInterleavePad
-    GstPadTemplate
-    GstPluginFeature
-      GstElementFactory
-      GstTypeFindFactory
-      GstIndexFactory
+    GstBus
+    GstClock
+      GstSystemClock
+        GstAudioClock
     GstElement
-      GstBin
-        GstPipeline
-          GstQTMoovRecover
-        GstSwitchSink
-          GstGConfVideoSink
-          GstGConfAudioSink
-        GstSwitchSrc
-          GstGConfVideoSrc
-          GstGConfAudioSrc
-        GstHalAudioSink
-        GstHalAudioSrc
-        GstRtpBin
-        GstAutoVideoSink
-        GstAutoVideoSrc
-        GstAutoAudioSink
-        GstAutoAudioSrc
-        GstPushFileSrc
-        GstRTSPSrc
-        GstRgVolume
-        GstAspectRatioCrop
-      GstCmmlEnc
-      GstCmmlDec
-      GstBaseSink
-        GstAASink
-        GstBaseAudioSink
-          GstPulseSink
-          GstJackAudioSink
-          GstAudioSink
-            GstEsdSink
-            GstOssSink
-            GstOss4Sink
-        GstCACASink
-        GstVideoSink
-          GstGdkPixbufSink
-        GstShout2send
-        GstTest
-        GstMultiFileSink
-        GstMultiUDPSink
-          GstUDPSink
-        GstDynUDPSink
-      GstBaseSrc
-        GstPushSrc
-          GstDV1394Src
-          GstHDV1394Src
-          GstSoupHTTPSrc
-          GstBaseAudioSrc
-            GstAudioSrc
-              GstPulseSrc
-              GstOssSrc
-              GstOss4Source
-            GstJackAudioSrc
-          GstV4l2Src
-          GstXImageSrc
-          GstMultiFileSrc
-          GstUDPSrc
-      GstWavpackParse
-      GstWavpackDec
-      GstWavpackEnc
-      GstDVDemux
-      GstDVDec
-      GstTagLibMux
-        GstId3v2Mux
-        GstApev2Mux
-      GstFlacEnc
-      GstFlacDec
-      GstFlacTag
-      GstCairoTextOverlay
-      GstBaseTransform
-        GstCairoTimeOverlay
-        GstVideoFilter
-          GstCairoOverlay
-          GstEdgeTV
-          GstAgingTV
-          GstDiceTV
-          GstWarpTV
-          GstShagadelicTV
-          GstVertigoTV
-          GstRevTV
-          GstQuarkTV
-          GstOpTV
-          GstRadioacTV
-          GstStreakTV
-          GstRippleTV
-          GstNavigationtest
-          GstGamma
-          GstVideoBalance
-          GstVideoFlip
-          GstSMPTEAlpha
-          GstAlpha
-          GstAlphaColor
-        GstPixbufScale
-        GstVideoBox
-        GstBreakMyData
-        GstCapsSetter
-        GstNavSeek
-        GstProgressReport
-        GstTagInject
-        GstCpuReport
-        GstLevel
-        GstAudioFilter
-          GstIirEqualizer
-            GstIirEqualizerNBands
-            GstIirEqualizer3Bands
-            GstIirEqualizer10Bands
-          GstSpectrum
-          GstAudioInvert
-          GstAudioKaraoke
-          GstAudioAmplify
-          GstAudioDynamic
-          GstAudioFXBaseIIRFilter
-            GstAudioChebLimit
-            GstAudioChebBand
-            GstAudioIIRFilter
-          GstAudioFXBaseFIRFilter
-            GstAudioWSincLimit
-            GstAudioWSincBand
-            GstAudioFIRFilter
-          GstAudioEcho
-        GstRgAnalysis
-        GstRgLimiter
-        GstVideoCrop
-        GstAudioPanorama
-      GstCairoRender
-      GstPulseMixer
-      GstSpeexEnc
-      GstSpeexDec
-      GstJpegEnc
-      GstJpegDec
-      GstSmokeEnc
-      GstSmokeDec
-      GstPngDec
-      GstPngEnc
-      GstGdkPixbuf
-      GstOssMixerElement
-      GstV4l2Radio
-      GstOss4Mixer
-      GstShapeWipe
+      Gst3GPPMux
+      GstALawDec
+      GstALawEnc
+      GstAsteriskh263
+      GstAuParse
       GstAviDemux
       GstAviMux
       GstAviSubtitle
-      GstRTPDepay
+      GstBaseParse
+        GstAacParse
+        GstAc3Parse
+        GstAmrParse
+        GstDcaParse
+        GstFlacParse
+        GstMpegAudioParse
       GstBaseRTPDepayload
-        GstRtpAC3Depay
         GstRTPBVDepay
-        GstRtpCELTDepay
         GstRTPDVDepay
-        GstRtpGSTDepay
+        GstRTPGSMDepay
+        GstRTPSirenDepay
         GstRTPiLBCDepay
+        GstRtpAC3Depay
+        GstRtpAMRDepay
+        GstRtpCELTDepay
         GstRtpG722Depay
         GstRtpG723Depay
         GstRtpG726Depay
         GstRtpG729Depay
-        GstRTPGSMDepay
-        GstRtpAMRDepay
-        GstRtpPcmaDepay
-        GstRtpPcmuDepay
-        GstRtpMPADepay
-        GstRtpMPARobustDepay
-        GstRtpMPVDepay
-        GstRtpH263PDepay
+        GstRtpGSTDepay
         GstRtpH263Depay
+        GstRtpH263PDepay
         GstRtpH264Depay
         GstRtpJ2KDepay
         GstRtpJPEGDepay
         GstRtpL16Depay
         GstRtpMP1SDepay
         GstRtpMP2TDepay
-        GstRtpMP4VDepay
         GstRtpMP4ADepay
         GstRtpMP4GDepay
+        GstRtpMP4VDepay
+        GstRtpMPADepay
+        GstRtpMPARobustDepay
+        GstRtpMPVDepay
+        GstRtpPcmaDepay
+        GstRtpPcmuDepay
         GstRtpQCELPDepay
         GstRtpQDM2Depay
-        GstRTPSirenDepay
         GstRtpSPEEXDepay
         GstRtpSV3VDepay
         GstRtpTheoraDepay
-        GstRtpVorbisDepay
         GstRtpVRawDepay
+        GstRtpVorbisDepay
         GstRtpXQTDepay
       GstBaseRTPPayload
-        GstRtpAC3Pay
         GstBaseRTPAudioPayload
           GstRTPBVPay
           GstRTPILBCPay
+          GstRTPSirenPay
           GstRtpG722Pay
           GstRtpG726Pay
-          GstRtpPcmuPay
-          GstRtpPcmaPay
           GstRtpL16Pay
-          GstRTPSirenPay
-        GstRtpCELTPay
+          GstRtpPcmaPay
+          GstRtpPcmuPay
         GstRTPDVPay
-        GstRtpGSTPay
         GstRTPG723Pay
         GstRTPG729Pay
         GstRTPGSMPay
-        GstRtpAMRPay
-        GstRtpMPAPay
+        GstRTPMP2TPay
         GstRTPMPVPay
+        GstRtpAC3Pay
+        GstRtpAMRPay
+        GstRtpCELTPay
+        GstRtpGSTPay
         GstRtpH263PPay
         GstRtpH263Pay
         GstRtpH264Pay
         GstRtpJ2KPay
         GstRtpJPEGPay
-        GstRTPMP2TPay
-        GstRtpMP4VPay
         GstRtpMP4APay
         GstRtpMP4GPay
+        GstRtpMP4VPay
+        GstRtpMPAPay
         GstRtpSPEEXPay
         GstRtpTheoraPay
-        GstRtpVorbisPay
         GstRtpVRawPay
-      GstAsteriskh263
-      GstGoom
-      GstGoom2k1
-      GstWavEnc
-      GstRtpJitterBuffer
-      GstRtpPtDemux
-      GstRtpSession
-      GstRtpSsrcDemux
-      GstRndBufferSize
+        GstRtpVorbisPay
+      GstBaseSink
+        GstAASink
+        GstBaseAudioSink
+          GstAudioSink
+            GstEsdSink
+            GstOss4Sink
+            GstOssSink
+          GstJackAudioSink
+          GstPulseSink
+        GstCACASink
+        GstDynUDPSink
+        GstMultiFileSink
+        GstMultiUDPSink
+          GstUDPSink
+        GstShout2send
+        GstTest
+        GstVideoSink
+          GstGdkPixbufSink
+          GstV4l2Sink
+      GstBaseSrc
+        GstPushSrc
+          GstBaseAudioSrc
+            GstAudioSrc
+              GstOss4Source
+              GstOssSrc
+              GstPulseSrc
+            GstJackAudioSrc
+          GstDV1394Src
+          GstHDV1394Src
+          GstMultiFileSrc
+          GstSoupHTTPSrc
+          GstUDPSrc
+          GstV4l2Src
+          GstXImageSrc
+      GstBaseTransform
+        GstAudioFilter
+          GstAudioAmplify
+          GstAudioDynamic
+          GstAudioEcho
+          GstAudioFXBaseFIRFilter
+            GstAudioFIRFilter
+            GstAudioWSincBand
+            GstAudioWSincLimit
+          GstAudioFXBaseIIRFilter
+            GstAudioChebBand
+            GstAudioChebLimit
+            GstAudioIIRFilter
+          GstAudioInvert
+          GstAudioKaraoke
+          GstIirEqualizer
+            GstIirEqualizer10Bands
+            GstIirEqualizer3Bands
+            GstIirEqualizerNBands
+          GstSpectrum
+        GstAudioPanorama
+        GstBreakMyData
+        GstCairoTimeOverlay
+        GstCapsSetter
+        GstCpuReport
+        GstLevel
+        GstNavSeek
+        GstPixbufScale
+        GstProgressReport
+        GstRgAnalysis
+        GstRgLimiter
+        GstTagInject
+        GstVideoBox
+        GstVideoCrop
+        GstVideoFilter
+          GstAgingTV
+          GstAlpha
+          GstAlphaColor
+          GstCairoOverlay
+          GstDiceTV
+          GstEdgeTV
+          GstGamma
+          GstNavigationtest
+          GstOpTV
+          GstQuarkTV
+          GstRadioacTV
+          GstRevTV
+          GstRippleTV
+          GstSMPTEAlpha
+          GstShagadelicTV
+          GstStreakTV
+          GstVertigoTV
+          GstVideoBalance
+          GstVideoFlip
+          GstWarpTV
+      GstBin
+        GstAspectRatioCrop
+        GstAutoAudioSink
+        GstAutoAudioSrc
+        GstAutoVideoSink
+        GstAutoVideoSrc
+        GstHalAudioSink
+        GstHalAudioSrc
+        GstPipeline
+          GstQTMoovRecover
+        GstPushFileSrc
+        GstRTSPSrc
+        GstRgVolume
+        GstRtpBin
+        GstSwitchSink
+          GstGConfAudioSink
+          GstGConfVideoSink
+        GstSwitchSrc
+          GstGConfAudioSrc
+          GstGConfVideoSrc
+      GstCairoRender
+      GstCairoTextOverlay
       GstCapsDebug
-      GstEFence
+      GstCmmlDec
+      GstCmmlEnc
       GstCutter
+      GstDVDec
+      GstDVDemux
+      GstDeinterlace
+      GstDeinterleave
+      GstEFence
+      GstFlacDec
+      GstFlacEnc
+      GstFlacTag
+      GstFlvDemux
+      GstFlvMux
+      GstFlxDec
+      GstGPPMux
+      GstGdkPixbuf
+      GstGoom
+      GstGoom2k1
+      GstICYDemux
+      GstISMLMux
+      GstImageFreeze
+      GstInterleave
+      GstJpegDec
+      GstJpegEnc
+      GstMJ2Mux
+      GstMP4Mux
       GstMatroskaDemux
-      GstMatroskaParse
       GstMatroskaMux
         GstWebMMux
-      GstRTPDec
-      GstSMPTE
-      GstAuParse
+      GstMatroskaParse
+      GstMonoscope
+      GstMuLawDec
+      GstMuLawEnc
       GstMultipartDemux
       GstMultipartMux
-      GstALawEnc
-      GstALawDec
-      GstMuLawEnc
-      GstMuLawDec
+      GstOss4Mixer
+      GstOssMixerElement
+      GstPngDec
+      GstPngEnc
+      GstPulseMixer
+      GstQTDemux
+      GstQTMux
+      GstRTPDec
+      GstRTPDepay
+      GstRndBufferSize
+      GstRtpJitterBuffer
+      GstRtpPtDemux
+      GstRtpSession
+      GstRtpSsrcDemux
+      GstSMPTE
+      GstShapeWipe
+      GstSmokeDec
+      GstSmokeEnc
+      GstSpeexDec
+      GstSpeexEnc
       GstTagDemux
         GstApeDemux
         GstID3Demux
-      GstFlxDec
-      GstDeinterlace
-      GstImageFreeze
-      GstBaseParse
-        GstAacParse
-        GstAmrParse
-        GstAc3Parse
-        GstDcaParse
-        GstFlacParse
-        GstMpegAudioParse
-      GstY4mEncode
-      GstInterleave
-      GstDeinterleave
-      GstWavParse
-      GstFlvDemux
-      GstFlvMux
-      GstQTDemux
-      GstQTMux
-      GstMP4Mux
-      GstISMLMux
-      Gst3GPPMux
-      GstGPPMux
-      GstMJ2Mux
-      GstICYDemux
+      GstTagLibMux
+        GstApev2Mux
+        GstId3v2Mux
+      GstV4l2Radio
       GstVideoMixer
       GstVideoMixer2
-    GstBus
-    GstTask
-    GstTaskPool
-    GstClock
-      GstSystemClock
-        GstAudioClock
+      GstWavEnc
+      GstWavParse
+      GstWavpackDec
+      GstWavpackEnc
+      GstWavpackParse
+      GstY4mEncode
+    GstPad
+      GstInterleavePad
+      GstVideoMixer2Pad
+      GstVideoMixerPad
+    GstPadTemplate
     GstPlugin
+    GstPluginFeature
+      GstElementFactory
+      GstIndexFactory
+      GstTypeFindFactory
     GstRegistry
     GstRingBuffer
-      GstAudioSrcRingBuffer
       GstAudioSinkRingBuffer
-      GstJackAudioSrcRingBuffer
+      GstAudioSrcRingBuffer
       GstJackAudioSinkRingBuffer
+      GstJackAudioSrcRingBuffer
+    GstTask
+    GstTaskPool
   GstSignalObject
-  GstCmmlTagStream
-  GstCmmlTagHead
-  GstCmmlTagClip
-  GstColorBalanceChannel
-  RTPSession
-  GstTunerNorm
   GstTunerChannel
-  GdkPixbuf
+  GstTunerNorm
+  RTPSession
 GInterface
+  GIcon
   GTypePlugin
   GstChildProxy
-  GstURIHandler
-  GstPropertyProbe
-  GstPreset
-  GstTagSetter
-  GstStreamVolume
+  GstColorBalance
   GstImplementsInterface
   GstMixer
+  GstNavigation
+  GstPreset
+  GstPropertyProbe
+  GstStreamVolume
+  GstTagSetter
+  GstTagXmpWriter
   GstTuner
-  GstColorBalance
+  GstURIHandler
   GstVideoOrientation
-  GstTagXmpWriter
-  GIcon
+  GstXOverlay
index 8cb7022..518366a 100644 (file)
@@ -1,62 +1,63 @@
+GdkPixbuf GIcon
+Gst3GPPMux GstTagSetter GstTagXmpWriter
+GstApev2Mux GstTagSetter
+GstAspectRatioCrop GstChildProxy
+GstAutoAudioSink GstChildProxy
+GstAutoAudioSrc GstChildProxy
+GstAutoVideoSink GstChildProxy
+GstAutoVideoSrc GstChildProxy
+GstAviMux GstTagSetter
 GstBin GstChildProxy
-GstPipeline GstChildProxy
-GstQTMoovRecover GstChildProxy
-GstSwitchSink GstChildProxy
-GstGConfVideoSink GstChildProxy
+GstDV1394Src GstURIHandler GstPropertyProbe
+GstDeinterlace GstChildProxy
+GstFlacEnc GstTagSetter GstPreset
+GstFlacTag GstTagSetter
+GstFlvMux GstTagSetter
 GstGConfAudioSink GstChildProxy
-GstSwitchSrc GstChildProxy
-GstGConfVideoSrc GstChildProxy
 GstGConfAudioSrc GstChildProxy
+GstGConfVideoSink GstChildProxy
+GstGConfVideoSrc GstChildProxy
+GstGPPMux GstTagSetter GstTagXmpWriter
+GstHDV1394Src GstURIHandler GstPropertyProbe
 GstHalAudioSink GstChildProxy
 GstHalAudioSrc GstChildProxy
-GstRtpBin GstChildProxy
-GstAutoVideoSink GstChildProxy
-GstAutoVideoSrc GstChildProxy
-GstAutoAudioSink GstChildProxy
-GstAutoAudioSrc GstChildProxy
+GstISMLMux GstTagSetter GstTagXmpWriter
+GstId3v2Mux GstTagSetter
+GstIirEqualizer GstChildProxy
+GstIirEqualizer10Bands GstChildProxy GstPreset
+GstIirEqualizer3Bands GstChildProxy GstPreset
+GstIirEqualizerNBands GstChildProxy
+GstMJ2Mux GstTagSetter GstTagXmpWriter
+GstMP4Mux GstTagSetter GstTagXmpWriter
+GstMatroskaMux GstTagSetter
+GstOss4Mixer GstImplementsInterface GstMixer GstPropertyProbe
+GstOss4Sink GstStreamVolume GstPropertyProbe
+GstOss4Source GstImplementsInterface GstMixer GstPropertyProbe
+GstOssMixerElement GstImplementsInterface GstMixer
+GstOssSrc GstImplementsInterface GstMixer
+GstPipeline GstChildProxy
+GstPulseMixer GstImplementsInterface GstMixer GstPropertyProbe
+GstPulseSink GstStreamVolume GstImplementsInterface GstPropertyProbe
+GstPulseSrc GstImplementsInterface GstMixer GstPropertyProbe
 GstPushFileSrc GstChildProxy GstURIHandler
+GstQTMoovRecover GstChildProxy
+GstQTMux GstTagSetter GstTagXmpWriter
 GstRTSPSrc GstChildProxy GstURIHandler
 GstRgVolume GstChildProxy
-GstAspectRatioCrop GstChildProxy
-GstPulseSink GstStreamVolume GstImplementsInterface GstPropertyProbe
-GstOss4Sink GstStreamVolume GstPropertyProbe
+GstRtpBin GstChildProxy
 GstShout2send GstTagSetter
-GstUDPSink GstURIHandler
-GstDV1394Src GstURIHandler GstPropertyProbe
-GstHDV1394Src GstURIHandler GstPropertyProbe
 GstSoupHTTPSrc GstURIHandler
-GstPulseSrc GstImplementsInterface GstMixer GstPropertyProbe
-GstOssSrc GstImplementsInterface GstMixer
-GstOss4Source GstImplementsInterface GstMixer GstPropertyProbe
-GstV4l2Src GstURIHandler GstImplementsInterface GstTuner GstColorBalance GstVideoOrientation GstPropertyProbe
-GstUDPSrc GstURIHandler
-GstWavpackEnc GstPreset
-GstTagLibMux GstTagSetter
-GstId3v2Mux GstTagSetter
-GstApev2Mux GstTagSetter
-GstFlacEnc GstTagSetter GstPreset
-GstFlacTag GstTagSetter
-GstVideoBalance GstImplementsInterface GstColorBalance
-GstIirEqualizer GstChildProxy
-GstIirEqualizerNBands GstChildProxy
-GstIirEqualizer3Bands GstChildProxy GstPreset
-GstIirEqualizer10Bands GstChildProxy GstPreset
-GstPulseMixer GstImplementsInterface GstMixer GstPropertyProbe
 GstSpeexEnc GstTagSetter GstPreset
-GstOssMixerElement GstImplementsInterface GstMixer
+GstSwitchSink GstChildProxy
+GstSwitchSrc GstChildProxy
+GstTagLibMux GstTagSetter
+GstUDPSink GstURIHandler
+GstUDPSrc GstURIHandler
 GstV4l2Radio GstURIHandler GstImplementsInterface GstTuner GstPropertyProbe
-GstOss4Mixer GstImplementsInterface GstMixer GstPropertyProbe
-GstAviMux GstTagSetter
-GstMatroskaMux GstTagSetter
-GstWebMMux GstTagSetter
-GstDeinterlace GstChildProxy
-GstFlvMux GstTagSetter
-GstQTMux GstTagSetter GstTagXmpWriter
-GstMP4Mux GstTagSetter GstTagXmpWriter
-GstISMLMux GstTagSetter GstTagXmpWriter
-Gst3GPPMux GstTagSetter GstTagXmpWriter
-GstGPPMux GstTagSetter GstTagXmpWriter
-GstMJ2Mux GstTagSetter GstTagXmpWriter
+GstV4l2Sink GstImplementsInterface GstXOverlay GstNavigation GstColorBalance GstVideoOrientation GstPropertyProbe
+GstV4l2Src GstURIHandler GstImplementsInterface GstTuner GstColorBalance GstVideoOrientation GstPropertyProbe
+GstVideoBalance GstImplementsInterface GstColorBalance
 GstVideoMixer GstChildProxy
 GstVideoMixer2 GstChildProxy
-GdkPixbuf GIcon
+GstWavpackEnc GstPreset
+GstWebMMux GstTagSetter
index ec5b5e2..5c212bb 100644 (file)
@@ -1,10 +1,11 @@
+GIcon GObject
 GstChildProxy GstObject
-GstTagSetter GstElement
-GstStreamVolume GObject
+GstColorBalance GstImplementsInterface GstElement
 GstImplementsInterface GstElement
 GstMixer GstImplementsInterface GstElement
+GstStreamVolume GObject
+GstTagSetter GstElement
+GstTagXmpWriter GstElement
 GstTuner GstImplementsInterface GstElement
-GstColorBalance GstImplementsInterface GstElement
 GstVideoOrientation GstImplementsInterface GstElement
-GstTagXmpWriter GstElement
-GIcon GObject
+GstXOverlay GstImplementsInterface GstElement
index 6eaee89..0f8a675 100644 (file)
@@ -1732,8 +1732,9 @@ gst_flac_dec_src_query (GstPad * pad, GstQuery * query)
 
       gst_query_parse_duration (query, &fmt, NULL);
 
-      /* try any demuxers before us first */
-      if (fmt == GST_FORMAT_TIME && peer && gst_pad_query (peer, query)) {
+      /* try any demuxers or parsers before us first */
+      if ((fmt == GST_FORMAT_TIME || fmt == GST_FORMAT_DEFAULT) &&
+          peer != NULL && gst_pad_query (peer, query)) {
         gst_query_parse_duration (query, NULL, &len);
         GST_DEBUG_OBJECT (flacdec, "peer returned duration %" GST_TIME_FORMAT,
             GST_TIME_ARGS (len));
index 0249e88..0c6c529 100644 (file)
@@ -198,6 +198,9 @@ static GstFlowReturn gst_flac_parse_parse_frame (GstBaseParse * parse,
     GstBaseParseFrame * frame);
 static GstFlowReturn gst_flac_parse_pre_push_frame (GstBaseParse * parse,
     GstBaseParseFrame * frame);
+static gboolean gst_flac_parse_convert (GstBaseParse * parse,
+    GstFormat src_format, gint64 src_value, GstFormat dest_format,
+    gint64 * dest_value);
 
 GST_BOILERPLATE (GstFlacParse, gst_flac_parse, GstBaseParse,
     GST_TYPE_BASE_PARSE);
@@ -244,6 +247,7 @@ gst_flac_parse_class_init (GstFlacParseClass * klass)
   baseparse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_parse_frame);
   baseparse_class->pre_push_frame =
       GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_frame);
+  baseparse_class->convert = GST_DEBUG_FUNCPTR (gst_flac_parse_convert);
 }
 
 static void
@@ -756,17 +760,15 @@ gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer)
   if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->min_blocksize, 16))
     goto error;
   if (flacparse->min_blocksize < 16) {
-    GST_ERROR_OBJECT (flacparse, "Invalid minimum block size: %u",
+    GST_WARNING_OBJECT (flacparse, "Invalid minimum block size: %u",
         flacparse->min_blocksize);
-    return FALSE;
   }
 
   if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->max_blocksize, 16))
     goto error;
   if (flacparse->max_blocksize < 16) {
-    GST_ERROR_OBJECT (flacparse, "Invalid maximum block size: %u",
+    GST_WARNING_OBJECT (flacparse, "Invalid maximum block size: %u",
         flacparse->max_blocksize);
-    return FALSE;
   }
 
   if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->min_framesize, 24))
@@ -796,10 +798,10 @@ gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer)
 
   if (!gst_bit_reader_get_bits_uint64 (&reader, &flacparse->total_samples, 36))
     goto error;
-  if (flacparse->total_samples)
-    gst_base_parse_set_duration (GST_BASE_PARSE (flacparse), GST_FORMAT_TIME,
-        GST_FRAMES_TO_CLOCK_TIME (flacparse->total_samples,
-            flacparse->samplerate), 0);
+  if (flacparse->total_samples) {
+    gst_base_parse_set_duration (GST_BASE_PARSE (flacparse),
+        GST_FORMAT_DEFAULT, flacparse->total_samples, 0);
+  }
 
   GST_DEBUG_OBJECT (flacparse, "STREAMINFO:\n"
       "\tmin/max blocksize: %u/%u,\n"
@@ -1353,3 +1355,35 @@ gst_flac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
 
   return GST_FLOW_OK;
 }
+
+static gboolean
+gst_flac_parse_convert (GstBaseParse * parse,
+    GstFormat src_format, gint64 src_value, GstFormat dest_format,
+    gint64 * dest_value)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
+
+  if (flacparse->samplerate > 0) {
+    if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_TIME) {
+      if (src_value != -1)
+        *dest_value =
+            gst_util_uint64_scale (src_value, GST_SECOND,
+            flacparse->samplerate);
+      else
+        *dest_value = -1;
+      return TRUE;
+    } else if (src_format == GST_FORMAT_TIME &&
+        dest_format == GST_FORMAT_DEFAULT) {
+      if (src_value != -1)
+        *dest_value =
+            gst_util_uint64_scale (src_value, flacparse->samplerate,
+            GST_SECOND);
+      else
+        *dest_value = -1;
+      return TRUE;
+    }
+  }
+
+  return GST_BASE_PARSE_CLASS (parent_class)->convert (parse, src_format,
+      src_value, dest_format, dest_value);
+}
index 715acb2..69e5273 100644 (file)
@@ -78,6 +78,9 @@ static gboolean gst_au_parse_add_srcpad (GstAuParse * auparse, GstCaps * caps);
 static gboolean gst_au_parse_src_query (GstPad * pad, GstQuery * query);
 static gboolean gst_au_parse_src_event (GstPad * pad, GstEvent * event);
 static gboolean gst_au_parse_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_au_parse_src_convert (GstAuParse * auparse,
+    GstFormat src_format, gint64 srcval, GstFormat dest_format,
+    gint64 * destval);
 
 GST_BOILERPLATE (GstAuParse, gst_au_parse, GstElement, GST_TYPE_ELEMENT);
 
@@ -251,7 +254,9 @@ gst_au_parse_parse_header (GstAuParse * auparse)
   }
 
   auparse->offset = GST_READ_UINT32_BE (head + 4);
-  /* Do not trust size, could be set to -1 : unknown */
+  /* Do not trust size, could be set to -1 : unknown
+   * otherwise: filesize = size + auparse->offset
+   */
   size = GST_READ_UINT32_BE (head + 8);
   auparse->encoding = GST_READ_UINT32_BE (head + 12);
   auparse->samplerate = GST_READ_UINT32_BE (head + 16);
@@ -425,6 +430,9 @@ gst_au_parse_chain (GstPad * pad, GstBuffer * buf)
   GstFlowReturn ret = GST_FLOW_OK;
   GstAuParse *auparse;
   gint avail, sendnow = 0;
+  gint64 timestamp;
+  gint64 duration;
+  gint64 offset;
 
   auparse = GST_AU_PARSE (gst_pad_get_parent (pad));
 
@@ -446,7 +454,7 @@ gst_au_parse_chain (GstPad * pad, GstBuffer * buf)
       goto out;
 
     gst_pad_push_event (auparse->srcpad,
-        gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_DEFAULT,
+        gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
             0, GST_CLOCK_TIME_NONE, 0));
   }
 
@@ -464,6 +472,7 @@ gst_au_parse_chain (GstPad * pad, GstBuffer * buf)
   if (sendnow > 0) {
     GstBuffer *outbuf;
     const guint8 *data;
+    gint64 pos;
 
     ret = gst_pad_alloc_buffer_and_set_caps (auparse->srcpad,
         auparse->buffer_offset, sendnow, GST_PAD_CAPS (auparse->srcpad),
@@ -478,6 +487,22 @@ gst_au_parse_chain (GstPad * pad, GstBuffer * buf)
     memcpy (GST_BUFFER_DATA (outbuf), data, sendnow);
     gst_adapter_flush (auparse->adapter, sendnow);
 
+    pos = auparse->buffer_offset - auparse->offset;
+    pos = MAX (pos, 0);
+
+    if (auparse->sample_size > 0 && auparse->samplerate > 0) {
+      gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos,
+          GST_FORMAT_DEFAULT, &offset);
+      gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos,
+          GST_FORMAT_TIME, &timestamp);
+      gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES,
+          sendnow, GST_FORMAT_TIME, &duration);
+
+      GST_BUFFER_OFFSET (outbuf) = offset;
+      GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+      GST_BUFFER_DURATION (outbuf) = duration;
+    }
+
     auparse->buffer_offset += sendnow;
 
     ret = gst_pad_push (auparse->srcpad, outbuf);
@@ -517,6 +542,9 @@ gst_au_parse_src_convert (GstAuParse * auparse, GstFormat src_format,
       /* fallthrough */
     case GST_FORMAT_DEFAULT:{
       switch (dest_format) {
+        case GST_FORMAT_DEFAULT:
+          *destval = srcval;
+          break;
         case GST_FORMAT_BYTES:
           *destval = srcval * samplesize;
           break;
@@ -532,8 +560,8 @@ gst_au_parse_src_convert (GstAuParse * auparse, GstFormat src_format,
     case GST_FORMAT_TIME:{
       switch (dest_format) {
         case GST_FORMAT_BYTES:
-          *destval =
-              gst_util_uint64_scale_int (srcval, rate * samplesize, GST_SECOND);
+          *destval = samplesize *
+              gst_util_uint64_scale_int (srcval, rate, GST_SECOND);
           break;
         case GST_FORMAT_DEFAULT:
           *destval = gst_util_uint64_scale_int (srcval, rate, GST_SECOND);
@@ -581,8 +609,7 @@ gst_au_parse_src_query (GstPad * pad, GstQuery * query)
       len -= auparse->offset;
       GST_OBJECT_UNLOCK (auparse);
 
-      ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, len,
-          format, &val);
+      ret = gst_au_parse_src_convert (auparse, bformat, len, format, &val);
 
       if (ret) {
         gst_query_set_duration (query, format, val);
@@ -611,6 +638,17 @@ gst_au_parse_src_query (GstPad * pad, GstQuery * query)
       }
       break;
     }
+    case GST_QUERY_SEEKING:{
+      GstFormat format;
+
+      gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+      /* FIXME: query duration in 'format'
+         gst_query_set_seeking (query, format, TRUE, 0, duration);
+       */
+      gst_query_set_seeking (query, format, TRUE, 0, GST_CLOCK_TIME_NONE);
+      ret = TRUE;
+      break;
+    }
     default:
       ret = gst_pad_query_default (pad, query);
       break;
@@ -628,6 +666,7 @@ gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event)
   GstFormat format;
   gdouble rate;
   gint64 start, stop;
+  gboolean res;
 
   gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
       &stop_type, &stop);
@@ -637,19 +676,79 @@ gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event)
     return FALSE;
   }
 
-  /* FIXME: implement seeking */
-  return FALSE;
+  res = gst_au_parse_src_convert (auparse, GST_FORMAT_TIME, start,
+      GST_FORMAT_BYTES, &start);
+
+  if (stop > 0) {
+    res = gst_au_parse_src_convert (auparse, GST_FORMAT_TIME, stop,
+        GST_FORMAT_BYTES, &stop);
+  }
+
+  GST_INFO_OBJECT (auparse,
+      "seeking: %" G_GINT64_FORMAT " ... %" G_GINT64_FORMAT, start, stop);
+
+  event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, start,
+      stop_type, stop);
+  res = gst_pad_push_event (auparse->sinkpad, event);
+  return res;
 }
 
 static gboolean
 gst_au_parse_sink_event (GstPad * pad, GstEvent * event)
 {
   GstAuParse *auparse;
-  gboolean ret;
+  gboolean ret = TRUE;
 
   auparse = GST_AU_PARSE (gst_pad_get_parent (pad));
 
   switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NEWSEGMENT:
+    {
+      GstFormat format;
+      gdouble rate, arate;
+      gint64 start, stop, time, offset = 0;
+      gboolean update;
+      GstSegment segment;
+      GstEvent *new_event = NULL;
+
+      gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
+      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
+          &start, &stop, &time);
+      gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
+          start, stop, time);
+
+      if (auparse->sample_size > 0) {
+        if (start > 0) {
+          offset = start;
+          start -= auparse->offset;
+          start = MAX (start, 0);
+        }
+        if (stop > 0) {
+          stop -= auparse->offset;
+          stop = MAX (stop, 0);
+        }
+        gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, start,
+            GST_FORMAT_TIME, &start);
+        gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, stop,
+            GST_FORMAT_TIME, &stop);
+      }
+
+      if (auparse->srcpad) {
+        GST_INFO_OBJECT (auparse,
+            "new segment: %" GST_TIME_FORMAT " ... %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+
+        new_event = gst_event_new_new_segment_full (update, rate, arate,
+            GST_FORMAT_TIME, start, stop, start);
+
+        ret = gst_pad_push_event (auparse->srcpad, new_event);
+      }
+
+      auparse->buffer_offset = offset;
+
+      gst_event_unref (event);
+      break;
+    }
     default:
       ret = gst_pad_event_default (pad, event);
       break;
index 845ccf8..def2b93 100644 (file)
@@ -1881,6 +1881,8 @@ gst_avi_demux_roundup_list (GstAviDemux * avi, GstBuffer ** buf)
 
     data = gst_buffer_map (obuf, NULL, NULL, GST_MAP_WRITE);
     gst_buffer_extract (*buf, 0, data, size);
+    /* assume 0 padding, at least makes outcome deterministic */
+    data[size] = 0;
     gst_buffer_unmap (obuf, data, size + 1);
     gst_buffer_replace (buf, obuf);
   }
index a9ed67f..4193490 100644 (file)
@@ -113,7 +113,7 @@ gst_rnd_buffer_size_base_init (gpointer g_class)
 
   gst_element_class_set_details_simple (gstelement_class, "Random buffer size",
       "Testing", "pull random sized buffers",
-      "Stefan Kost <stefan.kost@nokia.com>)");
+      "Stefan Kost <stefan.kost@nokia.com>");
 }
 
 
index ce76f72..415cb00 100644 (file)
@@ -2,6 +2,7 @@
  * GStreamer
  * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
  * Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
+ * Copyright (C) 2011 Robert Swain <robert.swain@collabora.co.uk>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -55,6 +56,9 @@ GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
 #define DEFAULT_METHOD          GST_DEINTERLACE_LINEAR
 #define DEFAULT_FIELDS          GST_DEINTERLACE_ALL
 #define DEFAULT_FIELD_LAYOUT    GST_DEINTERLACE_LAYOUT_AUTO
+#define DEFAULT_LOCKING         GST_DEINTERLACE_LOCKING_NONE
+#define DEFAULT_IGNORE_OBSCURE  TRUE
+#define DEFAULT_DROP_ORPHANS    TRUE
 
 enum
 {
@@ -63,9 +67,73 @@ enum
   PROP_METHOD,
   PROP_FIELDS,
   PROP_FIELD_LAYOUT,
+  PROP_LOCKING,
+  PROP_IGNORE_OBSCURE,
+  PROP_DROP_ORPHANS,
   PROP_LAST
 };
 
+#define GST_DEINTERLACE_BUFFER_STATE_P    (1<<0)
+#define GST_DEINTERLACE_BUFFER_STATE_I    (1<<1)
+#define GST_DEINTERLACE_BUFFER_STATE_TC_B (1<<2)
+#define GST_DEINTERLACE_BUFFER_STATE_TC_T (1<<3)
+#define GST_DEINTERLACE_BUFFER_STATE_TC_P (1<<4)
+#define GST_DEINTERLACE_BUFFER_STATE_TC_M (1<<5)
+#define GST_DEINTERLACE_BUFFER_STATE_DROP (1<<6)
+
+#define GST_ONE \
+  (GST_DEINTERLACE_BUFFER_STATE_TC_T | GST_DEINTERLACE_BUFFER_STATE_TC_B)
+#define GST_PRG \
+  (GST_DEINTERLACE_BUFFER_STATE_P | GST_DEINTERLACE_BUFFER_STATE_TC_P)
+#define GST_INT \
+  (GST_DEINTERLACE_BUFFER_STATE_I | GST_DEINTERLACE_BUFFER_STATE_TC_M)
+#define GST_DRP (GST_DEINTERLACE_BUFFER_STATE_DROP)
+
+#define GST_DEINTERLACE_OBSCURE_THRESHOLD 5
+
+static const TelecinePattern telecine_patterns[] = {
+  /* 60i -> 60p or 50i -> 50p (NOTE THE WEIRD RATIOS) */
+  {"1:1", 1, 2, 1, {GST_ONE,}},
+  /* 60i -> 30p or 50i -> 25p */
+  {"2:2", 1, 1, 1, {GST_INT,}},
+  /* 60i telecine -> 24p */
+  {"2:3", 5, 4, 5, {GST_PRG, GST_PRG, GST_ONE, GST_ONE, GST_PRG,}},
+  {"3:2:2:3", 5, 4, 5, {GST_PRG, GST_ONE, GST_INT, GST_ONE, GST_PRG,}},
+  {"2:3:3:2", 5, 4, 5, {GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,}},
+
+  /* The following patterns are obscure and are ignored if ignore-obscure is
+   * set to true. If any patterns are added above this line, check and edit
+   * GST_DEINTERLACE_OBSCURE_THRESHOLD */
+
+  /* 50i Euro pulldown -> 24p */
+  {"2-11:3", 25, 24, 25, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
+              GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
+              GST_PRG, GST_PRG, GST_ONE, GST_INT, GST_INT,
+              GST_INT, GST_INT, GST_INT, GST_INT, GST_INT,
+          GST_INT, GST_INT, GST_INT, GST_ONE, GST_PRG,}},
+  /* 60i (NTSC 30000/1001) -> 16p (16000/1001) */
+  {"3:4-3", 15, 8, 15, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,
+              GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_DRP,
+          GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
+  /* 50i (PAL) -> 16p */
+  {"3-7:4", 25, 16, 25, {GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,
+              GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
+              GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
+              GST_DRP, GST_PRG, GST_PRG, GST_DRP, GST_PRG,
+          GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,}},
+  /* NTSC 60i -> 18p */
+  {"3:3:4", 5, 3, 5, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
+  /* NTSC 60i -> 20p */
+  {"3:3", 3, 2, 3, {GST_PRG, GST_DRP, GST_PRG,}},
+  /* NTSC 60i -> 27.5 */
+  {"3:2-4", 11, 10, 11, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
+              GST_PRG, GST_ONE, GST_INT, GST_INT, GST_INT,
+          GST_ONE,}},
+  /* PAL 50i -> 27.5 */
+  {"1:2-4", 9, 9, 10, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_INT,
+          GST_INT, GST_INT, GST_INT, GST_INT,}},
+};
+
 static const GEnumValue methods_types[] = {
   {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
       "tomsmocomp"},
@@ -85,6 +153,21 @@ static const GEnumValue methods_types[] = {
   {0, NULL, NULL},
 };
 
+static const GEnumValue locking_types[] = {
+  {GST_DEINTERLACE_LOCKING_NONE,
+      "No pattern locking", "none"},
+  {GST_DEINTERLACE_LOCKING_AUTO,
+        "Choose passive/active locking depending on whether upstream is live",
+      "auto"},
+  {GST_DEINTERLACE_LOCKING_ACTIVE,
+        "Block until pattern-locked. Use accurate timestamp interpolation within a pattern repeat.",
+      "active"},
+  {GST_DEINTERLACE_LOCKING_PASSIVE,
+        "Do not block. Use naïve timestamp adjustment until pattern-locked based on state history.",
+      "passive"},
+  {0, NULL, NULL},
+};
+
 
 #define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
 static GType
@@ -160,6 +243,21 @@ gst_deinterlace_modes_get_type (void)
   return deinterlace_modes_type;
 }
 
+#define GST_TYPE_DEINTERLACE_LOCKING (gst_deinterlace_locking_get_type ())
+static GType
+gst_deinterlace_locking_get_type (void)
+{
+  static GType deinterlace_locking_type = 0;
+
+  if (!deinterlace_locking_type) {
+    deinterlace_locking_type =
+        g_enum_register_static ("GstDeinterlaceLocking", locking_types);
+  }
+
+  return deinterlace_locking_type;
+}
+
+
 #define DEINTERLACE_CAPS \
     GST_VIDEO_CAPS_YUV ("{ AYUV, Y444, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }") ";" \
     GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";" \
@@ -504,6 +602,51 @@ gst_deinterlace_class_init (GstDeinterlaceClass * klass)
           DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
       );
 
+  /**
+   * GstDeinterlace:locking
+   *
+   * This selects which approach to pattern locking is used which affects
+   * processing latency and accuracy of timestamp adjustment for telecine
+   * streams.
+   *
+   * Since: 0.10.29.
+   *
+   */
+  g_object_class_install_property (gobject_class, PROP_LOCKING,
+      g_param_spec_enum ("locking", "locking", "Pattern locking mode",
+          GST_TYPE_DEINTERLACE_LOCKING, DEFAULT_LOCKING,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstDeinterlace:ignore-obscure
+   *
+   * This selects whether to ignore obscure/rare telecine patterns.
+   * NTSC 2:3 pulldown variants are the only really common patterns.
+   *
+   * Since: 0.10.29.
+   *
+   */
+  g_object_class_install_property (gobject_class, PROP_IGNORE_OBSCURE,
+      g_param_spec_boolean ("ignore-obscure", "ignore-obscure",
+          "Ignore obscure telecine patterns (only consider P, I and 2:3 "
+          "variants).", DEFAULT_IGNORE_OBSCURE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstDeinterlace:drop-orphans
+   *
+   * This selects whether to drop orphan fields at the beginning of telecine
+   * patterns in active locking mode.
+   *
+   * Since: 0.10.29.
+   *
+   */
+  g_object_class_install_property (gobject_class, PROP_DROP_ORPHANS,
+      g_param_spec_boolean ("drop-orphans", "drop-orphans",
+          "Drop orphan fields at the beginning of telecine patterns in "
+          "active locking mode.", DEFAULT_DROP_ORPHANS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   element_class->change_state =
       GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
 }
@@ -571,7 +714,17 @@ gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
   gst_deinterlace_set_method (self, self->user_set_method_id);
   self->fields = DEFAULT_FIELDS;
   self->field_layout = DEFAULT_FIELD_LAYOUT;
-
+  self->locking = DEFAULT_LOCKING;
+  self->ignore_obscure = DEFAULT_IGNORE_OBSCURE;
+  self->drop_orphans = DEFAULT_DROP_ORPHANS;
+
+  self->low_latency = -1;
+  self->pattern = -1;
+  self->pattern_phase = -1;
+  self->pattern_count = 0;
+  self->output_count = 0;
+  self->pattern_base_ts = GST_CLOCK_TIME_NONE;
+  self->pattern_buf_dur = GST_CLOCK_TIME_NONE;
   self->still_frame_mode = FALSE;
 
   gst_deinterlace_reset (self);
@@ -606,6 +759,12 @@ gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
   memset (self->field_history, 0,
       GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
   self->history_count = 0;
+  memset (self->buf_states, 0,
+      GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY *
+      sizeof (GstDeinterlaceBufferState));
+  self->state_count = 0;
+  self->pattern_lock = FALSE;
+  self->pattern_refresh = TRUE;
 
   if (!self->still_frame_mode && self->last_buffer) {
     gst_buffer_unref (self->last_buffer);
@@ -650,6 +809,9 @@ gst_deinterlace_reset (GstDeinterlace * self)
   gst_deinterlace_reset_history (self, TRUE);
 
   gst_deinterlace_reset_qos (self);
+
+  self->need_more = FALSE;
+  self->have_eos = FALSE;
 }
 
 static void
@@ -698,6 +860,15 @@ gst_deinterlace_set_property (GObject * object, guint prop_id,
     case PROP_FIELD_LAYOUT:
       self->field_layout = g_value_get_enum (value);
       break;
+    case PROP_LOCKING:
+      self->locking = g_value_get_enum (value);
+      break;
+    case PROP_IGNORE_OBSCURE:
+      self->ignore_obscure = g_value_get_boolean (value);
+      break;
+    case PROP_DROP_ORPHANS:
+      self->drop_orphans = g_value_get_boolean (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
   }
@@ -726,6 +897,15 @@ gst_deinterlace_get_property (GObject * object, guint prop_id,
     case PROP_FIELD_LAYOUT:
       g_value_set_enum (value, self->field_layout);
       break;
+    case PROP_LOCKING:
+      g_value_set_enum (value, self->locking);
+      break;
+    case PROP_IGNORE_OBSCURE:
+      g_value_set_boolean (value, self->ignore_obscure);
+      break;
+    case PROP_DROP_ORPHANS:
+      g_value_set_boolean (value, self->drop_orphans);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
   }
@@ -746,6 +926,32 @@ gst_deinterlace_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static void
+gst_deinterlace_update_pattern_timestamps (GstDeinterlace * self)
+{
+  gint state_idx;
+  if (self->low_latency) {
+    /* in low-latency mode the buffer state history contains old buffer
+     * states as well as the current one and perhaps some future ones.
+     * the current buffer's state is given by the number of field pairs
+     * rounded up, minus 1. the below is equivalent */
+    state_idx = (self->history_count - 1) >> 1;
+  } else {
+    /* in high-latency mode state_count - 1 is the current buffer's state */
+    state_idx = self->state_count - 1;
+  }
+
+  self->pattern_base_ts = self->buf_states[state_idx].timestamp;
+  self->pattern_buf_dur =
+      (self->buf_states[state_idx].duration *
+      telecine_patterns[self->pattern].ratio_d) /
+      telecine_patterns[self->pattern].ratio_n;
+  GST_DEBUG_OBJECT (self,
+      "Starting a new pattern repeat with base ts %" GST_TIME_FORMAT
+      " and dur %" GST_TIME_FORMAT, GST_TIME_ARGS (self->pattern_base_ts),
+      GST_TIME_ARGS (self->pattern_buf_dur));
+}
+
 static GstBuffer *
 gst_deinterlace_pop_history (GstDeinterlace * self)
 {
@@ -759,6 +965,21 @@ gst_deinterlace_pop_history (GstDeinterlace * self)
   buffer = self->field_history[self->history_count - 1].buf;
 
   self->history_count--;
+  if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count
+          || GST_BUFFER_DATA (buffer) !=
+          GST_BUFFER_DATA (self->field_history[self->history_count - 1].buf))) {
+    if (!self->low_latency)
+      self->state_count--;
+    if (self->pattern_lock) {
+      self->pattern_count++;
+      if (self->pattern != -1
+          && self->pattern_count >= telecine_patterns[self->pattern].length) {
+        self->pattern_count = 0;
+        self->output_count = 0;
+        gst_deinterlace_update_pattern_timestamps (self);
+      }
+    }
+  }
 
   GST_DEBUG_OBJECT (self, "Returning buffer: %p %" GST_TIME_FORMAT
       " with duration %" GST_TIME_FORMAT " and size %u", buffer,
@@ -768,6 +989,78 @@ gst_deinterlace_pop_history (GstDeinterlace * self)
   return buffer;
 }
 
+typedef enum
+{
+  GST_DEINTERLACE_PROGRESSIVE,
+  GST_DEINTERLACE_INTERLACED,
+  GST_DEINTERLACE_TELECINE,
+} GstDeinterlaceInterlacingMethod;
+
+static GstDeinterlaceInterlacingMethod
+gst_deinterlace_get_interlacing_method (const GstCaps * caps)
+{
+  GstDeinterlaceInterlacingMethod method = 0;
+  gboolean interlaced;
+
+  /* check interlaced cap */
+  gst_structure_get_boolean (gst_caps_get_structure (caps, 0), "interlaced",
+      &interlaced);
+
+  method =
+      interlaced ? GST_DEINTERLACE_INTERLACED : GST_DEINTERLACE_PROGRESSIVE;
+
+  if (method == GST_DEINTERLACE_INTERLACED) {
+    const gchar *temp =
+        gst_structure_get_string (gst_caps_get_structure (caps, 0),
+        "interlacing-method");
+    if (temp && g_str_equal (temp, "telecine"))
+      method = GST_DEINTERLACE_TELECINE;
+  }
+
+  return method;
+}
+
+static void
+gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstBuffer * buffer,
+    guint8 * state, GstDeinterlaceInterlacingMethod * i_method)
+{
+  GstDeinterlaceInterlacingMethod interlacing_method;
+
+  if (!(i_method || state))
+    return;
+
+  interlacing_method =
+      gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (buffer));
+
+  if (state) {
+    if (interlacing_method == GST_DEINTERLACE_TELECINE) {
+      if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF)) {
+        *state = GST_DEINTERLACE_BUFFER_STATE_DROP;
+      } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD)) {
+        /* tc top if tff, tc bottom otherwise */
+        if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF)) {
+          *state = GST_DEINTERLACE_BUFFER_STATE_TC_T;
+        } else {
+          *state = GST_DEINTERLACE_BUFFER_STATE_TC_B;
+        }
+      } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_PROGRESSIVE)) {
+        *state = GST_DEINTERLACE_BUFFER_STATE_TC_P;
+      } else {
+        *state = GST_DEINTERLACE_BUFFER_STATE_TC_M;
+      }
+    } else {
+      if (interlacing_method == GST_DEINTERLACE_INTERLACED) {
+        *state = GST_DEINTERLACE_BUFFER_STATE_I;
+      } else {
+        *state = GST_DEINTERLACE_BUFFER_STATE_P;
+      }
+    }
+  }
+
+  if (i_method)
+    *i_method = interlacing_method;
+}
+
 static void
 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
 {
@@ -781,14 +1074,47 @@ gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
   GstBuffer *field1, *field2;
   guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
   gint field1_flags, field2_flags;
+  GstDeinterlaceInterlacingMethod interlacing_method;
+  guint8 buf_state;
 
   g_return_if_fail (self->history_count <
       GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
 
-  GST_DEBUG_OBJECT (self, "Pushing new buffer to the history: %" GST_TIME_FORMAT
-      " with duration %" GST_TIME_FORMAT " and size %u",
+  gst_deinterlace_get_buffer_state (self, buffer, &buf_state,
+      &interlacing_method);
+
+  GST_DEBUG_OBJECT (self,
+      "Pushing new buffer to the history: ptr %p at %" GST_TIME_FORMAT
+      " with duration %" GST_TIME_FORMAT
+      ", size %u, state %u, interlacing method %s", GST_BUFFER_DATA (buffer),
       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
-      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
+      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer),
+      buf_state,
+      interlacing_method ==
+      GST_DEINTERLACE_TELECINE ? "TC" : interlacing_method ==
+      GST_DEINTERLACE_INTERLACED ? "I" : "P");
+
+  /* move up for new state */
+  memmove (&self->buf_states[1], &self->buf_states[0],
+      (GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY - 1) *
+      sizeof (GstDeinterlaceBufferState));
+  self->buf_states[0].state = buf_state;
+  self->buf_states[0].timestamp = GST_BUFFER_TIMESTAMP (buffer);
+  self->buf_states[0].duration = GST_BUFFER_DURATION (buffer);
+  if (self->state_count < GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY)
+    self->state_count++;
+
+  if (buf_state == GST_DEINTERLACE_BUFFER_STATE_DROP) {
+    GST_DEBUG_OBJECT (self,
+        "Buffer contains only unneeded repeated fields, dropping and not"
+        "adding to field history");
+    gst_buffer_unref (buffer);
+    return;
+  }
+
+  /* telecine does not make use of repeated fields */
+  if (interlacing_method == GST_DEINTERLACE_TELECINE)
+    repeated = FALSE;
 
   for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
     self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
@@ -821,12 +1147,16 @@ gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
     field2_flags = PICTURE_INTERLACED_TOP;
   }
 
-  /* Timestamps are assigned to the field buffers under the assumption that
-     the timestamp of the buffer equals the first fields timestamp */
+  if (interlacing_method != GST_DEINTERLACE_TELECINE) {
+    /* Timestamps are assigned to the field buffers under the assumption that
+       the timestamp of the buffer equals the first fields timestamp */
 
-  timestamp = GST_BUFFER_TIMESTAMP (buffer);
-  GST_BUFFER_TIMESTAMP (field1) = timestamp;
-  GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
+    timestamp = GST_BUFFER_TIMESTAMP (buffer);
+    GST_BUFFER_TIMESTAMP (field1) = timestamp;
+    GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
+    if (repeated)
+      GST_BUFFER_TIMESTAMP (field2) += self->field_duration;
+  }
 
   if (repeated) {
     self->field_history[2].buf = field1;
@@ -943,84 +1273,442 @@ gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
   return TRUE;
 }
 
+static gboolean
+gst_deinterlace_fix_timestamps (GstDeinterlace * self,
+    GstDeinterlaceField * field1, GstDeinterlaceField * field2)
+{
+  GstDeinterlaceField *field3, *field4;
+  GstDeinterlaceInterlacingMethod interlacing_method;
+
+  if (self->pattern_lock && self->pattern > -1) {
+    /* accurate pattern-locked timestamp adjustment */
+    if (!self->pattern_count)
+      gst_deinterlace_update_pattern_timestamps (self);
+
+    GST_BUFFER_TIMESTAMP (field1->buf) =
+        self->pattern_base_ts + self->output_count * self->pattern_buf_dur;
+    GST_BUFFER_DURATION (field1->buf) = self->pattern_buf_dur;
+    self->output_count++;
+  } else {
+    /* naive (but low-latency) timestamp adjustment based on subsequent
+     * fields/buffers */
+    if (field2
+        && GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) {
+      if (GST_BUFFER_TIMESTAMP (field1->buf) +
+          GST_BUFFER_DURATION (field1->buf) ==
+          GST_BUFFER_TIMESTAMP (field2->buf)) {
+        GST_BUFFER_TIMESTAMP (field1->buf) =
+            GST_BUFFER_TIMESTAMP (field2->buf) =
+            (GST_BUFFER_TIMESTAMP (field1->buf) +
+            GST_BUFFER_TIMESTAMP (field2->buf)) / 2;
+      } else {
+        GST_BUFFER_TIMESTAMP (field2->buf) = GST_BUFFER_TIMESTAMP (field1->buf);
+      }
+    }
+
+    if (self->history_count < 3) {
+      GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 3)",
+          self->history_count);
+      return FALSE;
+    }
+
+    field3 = &self->field_history[self->history_count - 3];
+    interlacing_method =
+        gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (field3->buf));
+    if (interlacing_method == GST_DEINTERLACE_TELECINE) {
+      if (self->history_count < 4) {
+        GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 4)",
+            self->history_count);
+        return FALSE;
+      }
+
+      field4 = &self->field_history[self->history_count - 4];
+      if (GST_BUFFER_DATA (field3->buf) != GST_BUFFER_DATA (field4->buf)) {
+        /* telecine fields in separate buffers */
+        GST_BUFFER_TIMESTAMP (field3->buf) =
+            (GST_BUFFER_TIMESTAMP (field3->buf) +
+            GST_BUFFER_TIMESTAMP (field4->buf)) / 2;
+      }
+    }
+
+    GST_BUFFER_DURATION (field1->buf) =
+        GST_BUFFER_TIMESTAMP (field3->buf) - GST_BUFFER_TIMESTAMP (field1->buf);
+  }
+
+  GST_DEBUG_OBJECT (self,
+      "Field 1 adjusted to ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1->buf)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (field1->buf)));
+  return TRUE;
+}
+
+static void
+gst_deinterlace_get_pattern_lock (GstDeinterlace * self, gboolean * flush_one)
+{
+  /* loop over all possible patterns and all possible phases
+   * giving each a score. the highest score gets the lock */
+  /* the score is calculated as the number of matched buffers in the
+   * sequence starting at the phase offset with those from the history
+   * then the longest duration pattern match is taken. if there is more than
+   * one pattern matching all buffers, we take the longest pattern of those.
+   * matches to complete patterns are preferred. if no non-trivial pattern is
+   * matched, trivial patterns are tested. */
+  gint i, j, k, score, pattern, phase;
+  const gint state_count = self->state_count;
+  const gint n_required = self->ignore_obscure ?
+      GST_DEINTERLACE_OBSCURE_THRESHOLD :
+      GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
+
+  /* set unknown pattern as this is used in logic outside this function */
+  self->pattern = -1;
+
+  /* wait for more buffers */
+  if (!self->have_eos && state_count < n_required) {
+    GST_DEBUG_OBJECT (self, "Need more buffers in state history - %d/%d",
+        state_count, n_required);
+    return;
+  }
+
+  score = pattern = phase = -1;
+
+  /* loop over all patterns */
+  for (i = 0; i < G_N_ELEMENTS (telecine_patterns); i++) {
+    const guint8 length = telecine_patterns[i].length;
+
+    if (self->ignore_obscure && i >= GST_DEINTERLACE_OBSCURE_THRESHOLD)
+      break;
+
+    if (state_count < length)
+      continue;
+
+    /* loop over all phases */
+    for (j = 0; j < length; j++) {
+      /* low-latency mode looks at past buffers, high latency at future buffers */
+      const gint state_idx = (self->low_latency ? length : state_count) - 1;
+      /* loop over history, breaking on differing buffer states */
+      for (k = 0; k < length && k < state_count; k++) {
+        const guint8 hist = self->buf_states[state_idx - k].state;
+        const guint8 patt = telecine_patterns[i].states[(j + k) % length];
+        if (!(hist & patt))
+          break;
+      }
+
+      /* make complete matches more signficant */
+      if (k == length)
+        k += GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
+
+      /* take as new best pattern if the number of matched buffers is more than
+       * for other patterns */
+      if (k > score) {
+        score = k;
+        pattern = i;
+        phase = j;
+        if (self->low_latency) {
+          /* state_idx + 1 is the number of buffers yet to be pushed out
+           * so length - state_idx - 1 is the number of old buffers in the
+           * pattern */
+          phase = (phase + length - state_idx - 1) % length;
+        }
+      }
+    }
+  }
+
+  GST_DEBUG_OBJECT (self,
+      "Final pattern match result: pa %d, ph %d, l %d, s %d", pattern, phase,
+      telecine_patterns[pattern].length, score);
+  self->pattern = pattern;
+  self->pattern_phase = phase;
+  self->pattern_count = 0;
+  self->output_count = 0;
+  self->pattern_lock = TRUE;
+
+  /* check for the case that the first field of the pattern is an orphan */
+  if (pattern > 1
+      && telecine_patterns[pattern].states[phase] & (GST_ONE | GST_INT)) {
+    gint i = phase, field_count = 0;
+    guint8 state = telecine_patterns[pattern].states[i];
+
+    do {
+      if (state & GST_ONE) {
+        field_count++;
+      } else if (!(state & GST_DRP)) {
+        field_count += 2;
+      }
+      i++;
+      i %= telecine_patterns[pattern].length;
+      state = telecine_patterns[pattern].states[i];
+    } while (!(state & GST_PRG));
+
+    /* if field_count is odd, we have an orphan field at the beginning of the
+     * sequence
+     * note - don't do this in low-latency mode as we are somewhere within the
+     * pattern already */
+    if (!self->low_latency && (*flush_one = field_count & 1)) {
+      GST_DEBUG_OBJECT (self, "Orphan field detected at the beginning of the "
+          "pattern - it will be deinterlaced.");
+    }
+  }
+}
+
 static GstFlowReturn
 gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
 {
   GstClockTime timestamp;
-  GstFlowReturn ret = GST_FLOW_OK;
-  gint fields_required = 0;
-  gint cur_field_idx = 0;
+  GstFlowReturn ret;
+  gint fields_required;
+  gint cur_field_idx;
   GstBuffer *buf, *outbuf;
+  GstDeinterlaceField *field1, *field2;
+  GstDeinterlaceInterlacingMethod interlacing_method;
+  guint8 buf_state;
+  gboolean hl_no_lock;          /* indicates high latency timestamp adjustment but no pattern lock (could be ONEF or I) */
+  gboolean same_buffer;         /* are field1 and field2 in the same buffer? */
+  gboolean flush_one;           /* used for flushing one field when in high latency mode and not locked */
+  TelecinePattern pattern;
+  guint8 phase, count;
+  const GstDeinterlaceLocking locking = self->locking;
+
+restart:
+  ret = GST_FLOW_OK;
+  fields_required = 0;
+  cur_field_idx = 0;
+  hl_no_lock = FALSE;
+  same_buffer = FALSE;
+  flush_one = FALSE;
+  self->need_more = FALSE;
+  phase = self->pattern_phase;
+  count = self->pattern_count;
+
+  if (!self->history_count) {
+    GST_DEBUG_OBJECT (self, "History is empty, waiting for more buffers!");
+    goto need_more;
+  }
 
-  gst_deinterlace_set_method (self, self->user_set_method_id);
-  fields_required = gst_deinterlace_method_get_fields_required (self->method);
-
-  if (self->history_count < fields_required) {
-    if (flushing) {
-      /* FIXME: if there are any methods implemented that output different
-       * dimensions (e.g. half height) that require more than one field of
-       * history, it is desirable to degrade to something that outputs
-       * half-height also */
-      gst_deinterlace_set_method (self,
-          self->history_count >= 2 ?
-          GST_DEINTERLACE_VFIR : GST_DEINTERLACE_LINEAR);
+  field1 = &self->field_history[self->history_count - 1];
+
+  if (locking != GST_DEINTERLACE_LOCKING_NONE) {
+    if (!self->state_count) {
+      GST_ERROR_OBJECT (self,
+          "BROKEN! Fields in history + no states should not happen!");
+      return GST_FLOW_ERROR;
+    }
+
+    gst_deinterlace_get_buffer_state (self, field1->buf, &buf_state,
+        &interlacing_method);
+
+    if (self->pattern != -1)
+      pattern = telecine_patterns[self->pattern];
+
+    /* patterns 0 and 1 are interlaced, the rest are telecine */
+    if (self->pattern > 1)
+      interlacing_method = GST_DEINTERLACE_TELECINE;
+
+    if (self->pattern == -1 || self->pattern_refresh
+        || !(buf_state & pattern.states[(phase + count) % pattern.length])) {
+      /* no pattern, pattern refresh set or unexpected buffer state */
+      self->pattern_lock = FALSE;
+      self->pattern_refresh = TRUE;
+
+      /* refresh pattern lock */
+      gst_deinterlace_get_pattern_lock (self, &flush_one);
+
+      if (self->pattern != -1) {
+        /* locked onto a valid pattern so refresh complete */
+        GST_DEBUG_OBJECT (self, "Pattern locked! %s starting at %d",
+            telecine_patterns[self->pattern].nick, self->pattern_phase);
+        self->pattern_refresh = FALSE;
+      } else if (!self->low_latency) {
+        if (!self->pattern_lock) {
+          goto need_more;
+        } else {
+          hl_no_lock = TRUE;
+        }
+      }
+
+      /* setcaps on sink and src pads */
+      gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
+
+      if (flush_one && self->drop_orphans) {
+        GST_DEBUG_OBJECT (self, "Dropping orphan first field");
+        gst_buffer_unref (gst_deinterlace_pop_history (self));
+        goto restart;
+      }
+    }
+  } else {
+    gst_deinterlace_get_buffer_state (self, field1->buf, NULL,
+        &interlacing_method);
+  }
+
+  same_buffer = self->history_count >= 2
+      && (GST_BUFFER_DATA (field1->buf) ==
+      GST_BUFFER_DATA (self->field_history[self->history_count - 2].buf));
+
+  if ((flushing && self->history_count == 1) || (flush_one
+          && !self->drop_orphans) || (hl_no_lock && (self->history_count == 1
+              || !same_buffer))) {
+    GST_DEBUG_OBJECT (self, "Flushing one field using linear method");
+    gst_deinterlace_set_method (self, GST_DEINTERLACE_LINEAR);
+    fields_required = gst_deinterlace_method_get_fields_required (self->method);
+  } else if (interlacing_method == GST_DEINTERLACE_TELECINE
+      && (self->low_latency > 0 || self->pattern != -1 || (hl_no_lock
+              && same_buffer
+              && GST_BUFFER_FLAG_IS_SET (field1->buf,
+                  GST_VIDEO_BUFFER_PROGRESSIVE)))) {
+    /* telecined - we reconstruct frames by weaving pairs of fields */
+    fields_required = 2;
+    if (!flushing && self->history_count < fields_required) {
+      GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
+          self->history_count, fields_required);
+      goto need_more;
+    }
+
+    field2 = &self->field_history[self->history_count - 2];
+    if (!gst_deinterlace_fix_timestamps (self, field1, field2) && !flushing)
+      goto need_more;
+
+    if (same_buffer) {
+      /* telecine progressive */
+      GstBuffer *field1_buf;
+
+      GST_DEBUG_OBJECT (self,
+          "Frame type: Telecine Progressive; pushing buffer as a frame");
+      /* pop and push */
+      field1_buf = gst_deinterlace_pop_history (self);
+      /* field2 is the same buffer as field1, but we need to remove it from
+       * the history anyway */
+      gst_buffer_unref (gst_deinterlace_pop_history (self));
+      /* set the caps from the src pad on the buffer as they should be correct */
+      gst_buffer_set_caps (field1_buf, GST_PAD_CAPS (self->srcpad));
+      GST_DEBUG_OBJECT (self,
+          "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
+          GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)),
+          GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)),
+          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) +
+              GST_BUFFER_DURATION (field1_buf)));
+      return gst_pad_push (self->srcpad, field1_buf);
+    } else {
+      /* telecine fields in separate buffers */
+
+      /* check field1 and field2 buffer caps and flags are corresponding */
+      if (field1->flags == field2->flags) {
+        /* ERROR - fields are of same parity - what should be done here?
+         * perhaps deinterlace the tip field and start again? */
+        GST_ERROR_OBJECT (self, "Telecine mixed with fields of same parity!");
+      }
+      GST_DEBUG_OBJECT (self,
+          "Frame type: Telecine Mixed; weaving tip two fields into a frame");
+      /* set method to WEAVE */
+      gst_deinterlace_set_method (self, GST_DEINTERLACE_WEAVE);
+    }
+  } else if (interlacing_method == GST_DEINTERLACE_INTERLACED || (hl_no_lock
+          && interlacing_method == GST_DEINTERLACE_TELECINE && same_buffer
+          && !GST_BUFFER_FLAG_IS_SET (field1->buf,
+              GST_VIDEO_BUFFER_PROGRESSIVE))) {
+    gst_deinterlace_set_method (self, self->user_set_method_id);
+    fields_required = gst_deinterlace_method_get_fields_required (self->method);
+    if (flushing && self->history_count < fields_required) {
+      /* note: we already checked for flushing with history count == 1 above
+       * so we must have 2 or more fields in here */
+      gst_deinterlace_set_method (self, GST_DEINTERLACE_VFIR);
       fields_required =
           gst_deinterlace_method_get_fields_required (self->method);
       GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
           methods_types[self->method_id].value_nick);
-    } else {
-      /* Not enough fields in the history */
+    }
+
+    /* Not enough fields in the history */
+    if (self->history_count < fields_required) {
       GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
           self->history_count, fields_required);
-      return GST_FLOW_OK;
+      goto need_more;
     }
-  }
 
-  while (self->history_count >= fields_required) {
-    if (self->fields == GST_DEINTERLACE_ALL)
-      GST_DEBUG_OBJECT (self, "All fields");
-    else if (self->fields == GST_DEINTERLACE_TF)
-      GST_DEBUG_OBJECT (self, "Top fields");
-    else if (self->fields == GST_DEINTERLACE_BF)
-      GST_DEBUG_OBJECT (self, "Bottom fields");
-
-    cur_field_idx = self->history_count - fields_required;
-
-    if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
-            && self->fields == GST_DEINTERLACE_TF) ||
-        self->fields == GST_DEINTERLACE_ALL) {
-      GST_DEBUG_OBJECT (self, "deinterlacing top field");
-
-      /* create new buffer */
-      ret =
-          gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
-          self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
-      if (ret != GST_FLOW_OK)
-        return ret;
+    GST_DEBUG_OBJECT (self,
+        "Frame type: Interlaced; deinterlacing using %s method",
+        methods_types[self->method_id].value_nick);
+  } else {
+    GstBuffer *field1_buf;
 
-      if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf)
-          && !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
-              GST_BUFFER_CAPS (outbuf))) {
-        gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
-        GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
-            self->request_caps);
+    /* progressive */
+    fields_required = 2;
 
-        gst_buffer_unref (outbuf);
-        outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
+    /* Not enough fields in the history */
+    if (self->history_count < fields_required) {
+      GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
+          self->history_count, fields_required);
+      goto need_more;
+    }
 
-        if (!outbuf)
-          return GST_FLOW_ERROR;
+    field2 = &self->field_history[self->history_count - 2];
+    if (GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) {
+      /* ERROR - next two fields in field history are not one progressive buffer - weave? */
+      GST_ERROR_OBJECT (self,
+          "Progressive buffer but two fields at tip aren't in the same buffer!");
+    }
 
-        gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
-      }
+    GST_DEBUG_OBJECT (self,
+        "Frame type: Progressive; pushing buffer as a frame");
+    /* pop and push */
+    field1_buf = gst_deinterlace_pop_history (self);
+    /* field2 is the same buffer as field1, but we need to remove it from the
+     * history anyway */
+    gst_buffer_unref (gst_deinterlace_pop_history (self));
+    GST_DEBUG_OBJECT (self,
+        "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)),
+        GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)),
+        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) +
+            GST_BUFFER_DURATION (field1_buf)));
+    return gst_pad_push (self->srcpad, field1_buf);
+  }
 
-      g_return_val_if_fail (self->history_count - 1 -
-          gst_deinterlace_method_get_latency (self->method) >= 0,
-          GST_FLOW_ERROR);
+  if (self->fields == GST_DEINTERLACE_ALL
+      || interlacing_method == GST_DEINTERLACE_TELECINE)
+    GST_DEBUG_OBJECT (self, "All fields");
+  else if (self->fields == GST_DEINTERLACE_TF)
+    GST_DEBUG_OBJECT (self, "Top fields");
+  else if (self->fields == GST_DEINTERLACE_BF)
+    GST_DEBUG_OBJECT (self, "Bottom fields");
+
+  cur_field_idx = self->history_count - fields_required;
+
+  if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
+          && (self->fields == GST_DEINTERLACE_TF
+              || interlacing_method == GST_DEINTERLACE_TELECINE))
+      || self->fields == GST_DEINTERLACE_ALL) {
+    GST_DEBUG_OBJECT (self, "deinterlacing top field");
+
+    /* create new buffer */
+    ret =
+        gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
+        self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
+    if (ret != GST_FLOW_OK)
+      return ret;
+
+    if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) &&
+        !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
+            GST_BUFFER_CAPS (outbuf))) {
+      gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
+      GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
+          self->request_caps);
+
+      gst_buffer_unref (outbuf);
+      outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
+
+      if (!outbuf)
+        return GST_FLOW_ERROR;
+
+      gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
+    }
+
+    g_return_val_if_fail (self->history_count - 1 -
+        gst_deinterlace_method_get_latency (self->method) >= 0, GST_FLOW_ERROR);
 
-      buf =
-          self->field_history[self->history_count - 1 -
-          gst_deinterlace_method_get_latency (self->method)].buf;
+    buf =
+        self->field_history[self->history_count - 1 -
+        gst_deinterlace_method_get_latency (self->method)].buf;
+
+    if (interlacing_method != GST_DEINTERLACE_TELECINE) {
       timestamp = GST_BUFFER_TIMESTAMP (buf);
 
       GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
@@ -1028,79 +1716,110 @@ gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
         GST_BUFFER_DURATION (outbuf) = self->field_duration;
       else
         GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
-
-      /* Check if we need to drop the frame because of QoS */
-      if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
-        gst_buffer_unref (gst_deinterlace_pop_history (self));
-        gst_buffer_unref (outbuf);
-        outbuf = NULL;
-        ret = GST_FLOW_OK;
-      } else {
-        /* do magic calculus */
-        gst_deinterlace_method_deinterlace_frame (self->method,
-            self->field_history, self->history_count, outbuf);
-
-        gst_buffer_unref (gst_deinterlace_pop_history (self));
-
-        if (gst_deinterlace_clip_buffer (self, outbuf)) {
-          ret = gst_pad_push (self->srcpad, outbuf);
-        } else {
-          ret = GST_FLOW_OK;
-          gst_buffer_unref (outbuf);
-        }
-
-        outbuf = NULL;
-        if (ret != GST_FLOW_OK)
-          return ret;
-      }
+    } else {
+      GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+      GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
     }
-    /* no calculation done: remove excess field */
-    else if (self->field_history[cur_field_idx].flags ==
-        PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE_BF) {
-      GST_DEBUG_OBJECT (self, "Removing unused top field");
+
+    /* Check if we need to drop the frame because of QoS */
+    if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
       gst_buffer_unref (gst_deinterlace_pop_history (self));
-    }
+      gst_buffer_unref (outbuf);
+      outbuf = NULL;
+      ret = GST_FLOW_OK;
+    } else {
+      /* do magic calculus */
+      gst_deinterlace_method_deinterlace_frame (self->method,
+          self->field_history, self->history_count, outbuf);
 
-    cur_field_idx = self->history_count - fields_required;
-    if (self->history_count < fields_required)
-      break;
+      gst_buffer_unref (gst_deinterlace_pop_history (self));
 
-    /* deinterlace bottom_field */
-    if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
-            && self->fields == GST_DEINTERLACE_BF) ||
-        self->fields == GST_DEINTERLACE_ALL) {
-      GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
+      if (gst_deinterlace_clip_buffer (self, outbuf)) {
+        GST_DEBUG_OBJECT (self,
+            "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
+            GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+            GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
+            GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
+                GST_BUFFER_DURATION (outbuf)));
+        ret = gst_pad_push (self->srcpad, outbuf);
+      } else {
+        ret = GST_FLOW_OK;
+        gst_buffer_unref (outbuf);
+      }
 
-      /* create new buffer */
-      ret =
-          gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
-          self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
+      outbuf = NULL;
       if (ret != GST_FLOW_OK)
         return ret;
+      if (interlacing_method == GST_DEINTERLACE_TELECINE
+          && self->method_id == GST_DEINTERLACE_WEAVE) {
+        /* pop off the second field */
+        GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
+            self->history_count);
+        gst_buffer_unref (gst_deinterlace_pop_history (self));
+        interlacing_method = GST_DEINTERLACE_INTERLACED;
+        return ret;
+      }
+    }
 
-      if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf)
-          && !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
-              GST_BUFFER_CAPS (outbuf))) {
-        gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
-        GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
-            self->request_caps);
-
-        gst_buffer_unref (outbuf);
-        outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
+    if (flush_one && !self->drop_orphans) {
+      GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
+      goto restart;
+    }
+  }
+  /* no calculation done: remove excess field */
+  else if (self->field_history[cur_field_idx].flags ==
+      PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF
+          && interlacing_method != GST_DEINTERLACE_TELECINE)) {
+    GST_DEBUG_OBJECT (self, "Removing unused top field");
+    gst_buffer_unref (gst_deinterlace_pop_history (self));
+
+    if (flush_one && !self->drop_orphans) {
+      GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
+      goto restart;
+    }
+  }
 
-        if (!outbuf)
-          return GST_FLOW_ERROR;
+  cur_field_idx = self->history_count - fields_required;
+  if (self->history_count < fields_required)
+    return ret;
 
-        gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
-      }
+  /* deinterlace bottom_field */
+  if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
+          && (self->fields == GST_DEINTERLACE_BF
+              || interlacing_method == GST_DEINTERLACE_TELECINE))
+      || self->fields == GST_DEINTERLACE_ALL) {
+    GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
+
+    /* create new buffer */
+    ret =
+        gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
+        self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
+    if (ret != GST_FLOW_OK)
+      return ret;
+
+    if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) &&
+        !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
+            GST_BUFFER_CAPS (outbuf))) {
+      gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
+      GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
+          self->request_caps);
+
+      gst_buffer_unref (outbuf);
+      outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
+
+      if (!outbuf)
+        return GST_FLOW_ERROR;
+
+      gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
+    }
 
-      g_return_val_if_fail (self->history_count - 1 -
-          gst_deinterlace_method_get_latency (self->method) >= 0,
-          GST_FLOW_ERROR);
+    g_return_val_if_fail (self->history_count - 1 -
+        gst_deinterlace_method_get_latency (self->method) >= 0, GST_FLOW_ERROR);
 
-      buf =
-          self->field_history[self->history_count - 1 -
-          gst_deinterlace_method_get_latency (self->method)].buf;
+    buf =
+        self->field_history[self->history_count - 1 -
+        gst_deinterlace_method_get_latency (self->method)].buf;
+    if (interlacing_method != GST_DEINTERLACE_TELECINE) {
       timestamp = GST_BUFFER_TIMESTAMP (buf);
 
       GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
@@ -1108,47 +1827,111 @@ gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
         GST_BUFFER_DURATION (outbuf) = self->field_duration;
       else
         GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
+    } else {
+      GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+      GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
+    }
 
-      /* Check if we need to drop the frame because of QoS */
-      if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
-        gst_buffer_unref (gst_deinterlace_pop_history (self));
-        gst_buffer_unref (outbuf);
-        outbuf = NULL;
-        ret = GST_FLOW_OK;
-      } else {
-        /* do magic calculus */
-        gst_deinterlace_method_deinterlace_frame (self->method,
-            self->field_history, self->history_count, outbuf);
+    /* Check if we need to drop the frame because of QoS */
+    if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
+      gst_buffer_unref (gst_deinterlace_pop_history (self));
+      gst_buffer_unref (outbuf);
+      outbuf = NULL;
+      ret = GST_FLOW_OK;
+    } else {
+      /* do magic calculus */
+      gst_deinterlace_method_deinterlace_frame (self->method,
+          self->field_history, self->history_count, outbuf);
 
-        gst_buffer_unref (gst_deinterlace_pop_history (self));
+      gst_buffer_unref (gst_deinterlace_pop_history (self));
 
-        if (gst_deinterlace_clip_buffer (self, outbuf)) {
-          ret = gst_pad_push (self->srcpad, outbuf);
-        } else {
-          ret = GST_FLOW_OK;
-          gst_buffer_unref (outbuf);
-        }
+      if (gst_deinterlace_clip_buffer (self, outbuf)) {
+        GST_DEBUG_OBJECT (self,
+            "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
+            GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+            GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
+            GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
+                GST_BUFFER_DURATION (outbuf)));
+        ret = gst_pad_push (self->srcpad, outbuf);
+      } else {
+        ret = GST_FLOW_OK;
+        gst_buffer_unref (outbuf);
+      }
 
-        outbuf = NULL;
-        if (ret != GST_FLOW_OK)
-          return ret;
+      outbuf = NULL;
+      if (ret != GST_FLOW_OK)
+        return ret;
+      if (interlacing_method == GST_DEINTERLACE_TELECINE
+          && self->method_id == GST_DEINTERLACE_WEAVE) {
+        /* pop off the second field */
+        GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
+            self->history_count);
+        gst_buffer_unref (gst_deinterlace_pop_history (self));
+        interlacing_method = GST_DEINTERLACE_INTERLACED;
+        return ret;
       }
     }
-    /* no calculation done: remove excess field */
-    else if (self->field_history[cur_field_idx].flags ==
-        PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE_TF) {
-      GST_DEBUG_OBJECT (self, "Removing unused bottom field");
-      gst_buffer_unref (gst_deinterlace_pop_history (self));
+
+    if (flush_one && !self->drop_orphans) {
+      GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
+      goto restart;
     }
   }
+  /* no calculation done: remove excess field */
+  else if (self->field_history[cur_field_idx].flags ==
+      PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF
+          && interlacing_method != GST_DEINTERLACE_TELECINE)) {
+    GST_DEBUG_OBJECT (self, "Removing unused bottom field");
+    gst_buffer_unref (gst_deinterlace_pop_history (self));
+
+    if (flush_one && !self->drop_orphans) {
+      GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
+      goto restart;
+    }
+  }
+
+  return ret;
 
+need_more:
+  self->need_more = TRUE;
   return ret;
 }
 
+static gboolean
+gst_deinterlace_get_latency (GstDeinterlace * self)
+{
+  if (self->locking == GST_DEINTERLACE_LOCKING_AUTO) {
+    gboolean res;
+    GstQuery *query;
+
+    query = gst_query_new_latency ();
+    if ((res = gst_pad_peer_query (self->sinkpad, query))) {
+      gboolean is_live;
+      /* if upstream is live, we use low-latency passive locking mode
+       * else high-latency active locking mode */
+      gst_query_parse_latency (query, &is_live, NULL, NULL);
+      GST_DEBUG_OBJECT (self, "Latency query indicates stream is %s",
+          is_live ? "live - using passive locking" :
+          "not live - using active locking");
+      gst_query_unref (query);
+      return is_live;
+    } else {
+      /* conservatively use passive locking if the query fails */
+      GST_WARNING_OBJECT (self,
+          "Latency query failed - fall back to using passive locking");
+      gst_query_unref (query);
+      return TRUE;
+    }
+  } else {
+    return self->locking - 2;
+  }
+}
+
 static GstFlowReturn
 gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
 {
   GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad));
+  GstFlowReturn ret = GST_FLOW_OK;
 
   GST_OBJECT_LOCK (self);
   if (self->reconfigure) {
@@ -1166,8 +1949,23 @@ gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
     GST_OBJECT_UNLOCK (self);
   }
 
-  if (self->still_frame_mode || self->passthrough)
+  GST_DEBUG_OBJECT (self,
+      "[IN] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
+
+  if (self->still_frame_mode || self->passthrough) {
+    GST_DEBUG_OBJECT (self,
+        "Frame type: Progressive?; pushing buffer using pass-through");
+    GST_DEBUG_OBJECT (self,
+        "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+        GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
+        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
+
     return gst_pad_push (self->srcpad, buf);
+  }
 
   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
     GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
@@ -1177,7 +1975,11 @@ gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
   gst_deinterlace_push_history (self, buf);
   buf = NULL;
 
-  return gst_deinterlace_output_frame (self, FALSE);
+  do {
+    ret = gst_deinterlace_output_frame (self, FALSE);
+  } while (!self->need_more && self->history_count > 0 && ret == GST_FLOW_OK);
+
+  return ret;
 }
 
 static gint
@@ -1386,6 +2188,23 @@ gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
   gboolean res = TRUE;
   GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
   GstCaps *srccaps;
+  GstDeinterlaceInterlacingMethod interlacing_method;
+
+  if (self->locking != GST_DEINTERLACE_LOCKING_NONE) {
+    if (self->low_latency == -1)
+      self->low_latency = gst_deinterlace_get_latency (self);
+
+    if (self->pattern_lock) {
+      /* refresh has been successful - we have a lock now */
+      self->pattern_refresh = FALSE;
+    } else {
+      /* if we were not refreshing (!pattern_refresh) the caps have changed
+       * so we need to refresh and we don't have a lock anymore
+       * otherwise we have pattern_fresh and !pattern_lock anyway */
+      self->pattern_refresh = TRUE;
+      self->pattern_lock = FALSE;
+    }
+  }
 
   res =
       gst_video_format_parse_caps (caps, &self->format, &self->width,
@@ -1398,27 +2217,51 @@ gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
 
   gst_deinterlace_update_passthrough (self);
 
-  if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
-    gint fps_n = self->fps_n, fps_d = self->fps_d;
-
-    if (!gst_fraction_double (&fps_n, &fps_d, FALSE))
-      goto invalid_caps;
+  interlacing_method = gst_deinterlace_get_interlacing_method (caps);
 
+  if (self->pattern_lock) {
     srccaps = gst_caps_copy (caps);
-
-    gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
-        fps_d, NULL);
+    if (self->pattern != -1
+        && G_UNLIKELY (!gst_util_fraction_multiply (self->fps_n, self->fps_d,
+                telecine_patterns[self->pattern].ratio_n,
+                telecine_patterns[self->pattern].ratio_d, &self->fps_n,
+                &self->fps_d)))
+      GST_ERROR_OBJECT (self,
+          "Multiplying the framerate by the telecine pattern ratio overflowed!");
+    gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, self->fps_n,
+        self->fps_d, NULL);
+  } else if (self->low_latency > 0) {
+    if (interlacing_method == GST_DEINTERLACE_TELECINE) {
+      /* for initial buffers of a telecine pattern, until there is a lock we
+       * we output naïvely adjusted timestamps */
+      srccaps = gst_caps_copy (caps);
+      gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
+    } else if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
+      gint fps_n = self->fps_n, fps_d = self->fps_d;
+
+      if (!gst_fraction_double (&fps_n, &fps_d, FALSE))
+        goto invalid_caps;
+
+      srccaps = gst_caps_copy (caps);
+
+      gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
+          fps_d, NULL);
+    } else {
+      srccaps = gst_caps_ref (caps);
+    }
   } else {
+    /* in high latency pattern locking mode if we don't have a pattern lock,
+     * the sink pad caps are the best we know */
     srccaps = gst_caps_ref (caps);
   }
 
   if (self->mode != GST_DEINTERLACE_MODE_DISABLED) {
     srccaps = gst_caps_make_writable (srccaps);
+    gst_structure_remove_field (gst_caps_get_structure (srccaps, 0),
+        "interlacing-method");
     gst_caps_set_simple (srccaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
   }
 
-  gst_deinterlace_reset_history (self, FALSE);
-
   if (!gst_pad_set_caps (self->srcpad, srccaps))
     goto caps_not_accepted;
 
@@ -1475,8 +2318,8 @@ gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
       gint64 start, end, base;
       gdouble rate, applied_rate;
 
-      gst_event_parse_new_segment_full (event, &is_update, &rate, &applied_rate,
-          &fmt, &start, &end, &base);
+      gst_event_parse_new_segment_full (event, &is_update, &rate,
+          &applied_rate, &fmt, &start, &end, &base);
 
       gst_deinterlace_reset_qos (self);
       gst_deinterlace_reset_history (self, FALSE);
@@ -1524,6 +2367,7 @@ gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
     }
       /* fall through */
     case GST_EVENT_EOS:
+      self->have_eos = TRUE;
       gst_deinterlace_reset_history (self, FALSE);
 
       /* fall through */
index df996f8..ac97a55 100644 (file)
@@ -43,8 +43,6 @@ G_BEGIN_DECLS
 typedef struct _GstDeinterlace GstDeinterlace;
 typedef struct _GstDeinterlaceClass GstDeinterlaceClass;
 
-#define GST_DEINTERLACE_MAX_FIELD_HISTORY 10
-
 typedef enum
 {
   GST_DEINTERLACE_TOMSMOCOMP,
@@ -79,6 +77,39 @@ typedef enum {
   GST_DEINTERLACE_MODE_DISABLED
 } GstDeinterlaceMode;
 
+typedef enum
+{
+  GST_DEINTERLACE_LOCKING_NONE,
+  GST_DEINTERLACE_LOCKING_AUTO,
+  GST_DEINTERLACE_LOCKING_ACTIVE,
+  GST_DEINTERLACE_LOCKING_PASSIVE,
+} GstDeinterlaceLocking;
+
+#define GST_DEINTERLACE_MAX_FIELD_HISTORY 10
+#define GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY 50
+/* check max field history is large enough */
+#if GST_DEINTERLACE_MAX_FIELD_HISTORY < GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY * 3
+#undef GST_DEINTERLACE_MAX_FIELD_HISTORY
+#define GST_DEINTERLACE_MAX_FIELD_HISTORY (GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY * 3)
+#endif
+
+typedef struct _TelecinePattern TelecinePattern;
+struct _TelecinePattern
+{
+  const gchar *nick;
+  guint8 length;
+  guint8 ratio_n, ratio_d;
+  guint8 states[GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY];
+};
+
+typedef struct _GstDeinterlaceBufferState GstDeinterlaceBufferState;
+struct _GstDeinterlaceBufferState
+{
+  GstClockTime timestamp;
+  GstClockTime duration;
+  guint8 state;
+};
+
 struct _GstDeinterlace
 {
   GstElement parent;
@@ -92,8 +123,10 @@ struct _GstDeinterlace
 
   GstDeinterlaceFields fields;
 
-  GstDeinterlaceMethods method_id; /* current state (differs when flushing) */
-  GstDeinterlaceMethods user_set_method_id; /* property value */
+  /* current state (differs when flushing/inverse telecine using weave) */
+  GstDeinterlaceMethods method_id;
+  /* property value */
+  GstDeinterlaceMethods user_set_method_id;
   GstDeinterlaceMethod *method;
 
   GstVideoFormat format;
@@ -134,6 +167,24 @@ struct _GstDeinterlace
   gboolean reconfigure;
   GstDeinterlaceMode new_mode;
   GstDeinterlaceFields new_fields;
+
+  GstDeinterlaceLocking locking;
+  gint low_latency;
+  gboolean drop_orphans;
+  gboolean ignore_obscure;
+  gboolean pattern_lock;
+  gboolean pattern_refresh;
+  GstDeinterlaceBufferState buf_states[GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY];
+  gint state_count;
+  gint pattern;
+  guint8 pattern_phase;
+  guint8 pattern_count;
+  guint8 output_count;
+  GstClockTime pattern_base_ts;
+  GstClockTime pattern_buf_dur;
+
+  gboolean need_more;
+  gboolean have_eos;
 };
 
 struct _GstDeinterlaceClass
index 42056fb..f29015e 100644 (file)
@@ -2723,6 +2723,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
             ("We got less than expected (received %u, wanted %u, offset %"
                 G_GUINT64_FORMAT ")",
                 GST_BUFFER_SIZE (moov), (guint) length, cur_offset));
+        gst_buffer_unref (moov);
         ret = GST_FLOW_ERROR;
         goto beach;
       }
@@ -9320,6 +9321,7 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
     case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
       _codec ("On2 VP8");
       caps = gst_caps_from_string ("video/x-vp8");
+      break;
     case FOURCC_ovc1:
       _codec ("VC-1");
       caps = gst_caps_new_simple ("video/x-wmv",
index 195c680..7d56973 100644 (file)
@@ -8,6 +8,7 @@ libgstmatroska_la_SOURCES = \
        matroska-parse.c \
        matroska-ids.c \
        matroska-mux.c \
+       matroska-read-common.c \
        webm-mux.c \
        lzo.c
 
@@ -19,6 +20,7 @@ noinst_HEADERS = \
        matroska-parse.h \
        matroska-ids.h \
        matroska-mux.h \
+       matroska-read-common.h \
        webm-mux.h \
        lzo.h
 
index 788c8dd..02a0ffc 100644 (file)
@@ -2,6 +2,7 @@
  * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
  * (c) 2006 Tim-Philipp Müller <tim centricular net>
  * (c) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
  *
  * matroska-demux.c: matroska file/stream demuxer
  *
 
 #include <gst/base/gsttypefindhelper.h>
 
-#ifdef HAVE_ZLIB
-#include <zlib.h>
-#endif
-
-#ifdef HAVE_BZ2
-#include <bzlib.h>
-#endif
-
 #include <gst/pbutils/pbutils.h>
 
-#include "lzo.h"
-
 #include "matroska-demux.h"
 #include "matroska-ids.h"
 
@@ -208,9 +199,9 @@ gst_matroska_demux_finalize (GObject * object)
 {
   GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (object);
 
-  if (demux->src) {
-    g_ptr_array_free (demux->src, TRUE);
-    demux->src = NULL;
+  if (demux->common.src) {
+    g_ptr_array_free (demux->common.src, TRUE);
+    demux->common.src = NULL;
   }
 
   if (demux->global_tags) {
@@ -263,11 +254,11 @@ gst_matroska_demux_init (GstMatroskaDemux * demux,
   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
 
   /* initial stream no. */
-  demux->src = NULL;
+  demux->common.src = NULL;
 
   demux->writing_app = NULL;
   demux->muxing_app = NULL;
-  demux->index = NULL;
+  demux->common.index = NULL;
   demux->global_tags = NULL;
 
   demux->adapter = gst_adapter_new ();
@@ -325,9 +316,10 @@ gst_matroska_demux_combine_flows (GstMatroskaDemux * demux,
     goto done;
 
   /* only return NOT_LINKED if all other pads returned NOT_LINKED */
-  g_assert (demux->src->len == demux->num_streams);
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *ostream = g_ptr_array_index (demux->src, i);
+  g_assert (demux->common.src->len == demux->common.num_streams);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *ostream = g_ptr_array_index (demux->common.src,
+        i);
 
     if (ostream == NULL)
       continue;
@@ -360,13 +352,14 @@ gst_matroska_demux_reset (GstElement * element)
   GST_DEBUG_OBJECT (demux, "Resetting state");
 
   /* reset input */
-  demux->state = GST_MATROSKA_DEMUX_STATE_START;
+  demux->common.state = GST_MATROSKA_READ_STATE_START;
 
   /* clean up existing streams */
-  if (demux->src) {
-    g_assert (demux->src->len == demux->num_streams);
-    for (i = 0; i < demux->src->len; i++) {
-      GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i);
+  if (demux->common.src) {
+    g_assert (demux->common.src->len == demux->common.num_streams);
+    for (i = 0; i < demux->common.src->len; i++) {
+      GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src,
+          i);
 
       if (context->pad != NULL)
         gst_element_remove_pad (GST_ELEMENT (demux), context->pad);
@@ -374,11 +367,11 @@ gst_matroska_demux_reset (GstElement * element)
       gst_caps_replace (&context->caps, NULL);
       gst_matroska_track_free (context);
     }
-    g_ptr_array_free (demux->src, TRUE);
+    g_ptr_array_free (demux->common.src, TRUE);
   }
-  demux->src = g_ptr_array_new ();
+  demux->common.src = g_ptr_array_new ();
 
-  demux->num_streams = 0;
+  demux->common.num_streams = 0;
   demux->num_a_streams = 0;
   demux->num_t_streams = 0;
   demux->num_v_streams = 0;
@@ -390,9 +383,9 @@ gst_matroska_demux_reset (GstElement * element)
   demux->muxing_app = NULL;
 
   /* reset indexes */
-  if (demux->index) {
-    g_array_free (demux->index, TRUE);
-    demux->index = NULL;
+  if (demux->common.index) {
+    g_array_free (demux->common.index, TRUE);
+    demux->common.index = NULL;
   }
 
   if (demux->clusters) {
@@ -402,10 +395,10 @@ gst_matroska_demux_reset (GstElement * element)
 
   /* reset timers */
   demux->clock = NULL;
-  demux->time_scale = 1000000;
+  demux->common.time_scale = 1000000;
   demux->created = G_MININT64;
 
-  demux->index_parsed = FALSE;
+  demux->common.index_parsed = FALSE;
   demux->tracks_parsed = FALSE;
   demux->segmentinfo_parsed = FALSE;
   demux->attachments_parsed = FALSE;
@@ -450,11 +443,11 @@ gst_matroska_demux_reset (GstElement * element)
     demux->new_segment = NULL;
   }
 
-  if (demux->element_index) {
-    gst_object_unref (demux->element_index);
-    demux->element_index = NULL;
+  if (demux->common.element_index) {
+    gst_object_unref (demux->common.element_index);
+    demux->common.element_index = NULL;
   }
-  demux->element_index_writer_id = -1;
+  demux->common.element_index_writer_id = -1;
 
   if (demux->global_tags) {
     gst_tag_list_free (demux->global_tags);
@@ -584,27 +577,6 @@ gst_matroska_demux_get_length (GstMatroskaDemux * demux)
 }
 
 static gint
-gst_matroska_demux_stream_from_num (GstMatroskaDemux * demux, guint track_num)
-{
-  guint n;
-
-  g_assert (demux->src->len == demux->num_streams);
-  for (n = 0; n < demux->src->len; n++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, n);
-
-    if (context->num == track_num) {
-      return n;
-    }
-  }
-
-  if (n == demux->num_streams)
-    GST_WARNING_OBJECT (demux,
-        "Failed to find corresponding pad for tracknum %d", track_num);
-
-  return -1;
-}
-
-static gint
 gst_matroska_demux_encoding_cmp (GstMatroskaTrackEncoding * a,
     GstMatroskaTrackEncoding * b)
 {
@@ -794,176 +766,6 @@ gst_matroska_demux_read_track_encoding (GstMatroskaDemux * demux,
 }
 
 static gboolean
-gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
-    guint8 ** data_out, guint * size_out,
-    GstMatroskaTrackCompressionAlgorithm algo)
-{
-  guint8 *new_data = NULL;
-  guint new_size = 0;
-  guint8 *data = *data_out;
-  guint size = *size_out;
-  gboolean ret = TRUE;
-
-  if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB) {
-#ifdef HAVE_ZLIB
-    /* zlib encoded data */
-    z_stream zstream;
-    guint orig_size;
-    int result;
-
-    orig_size = size;
-    zstream.zalloc = (alloc_func) 0;
-    zstream.zfree = (free_func) 0;
-    zstream.opaque = (voidpf) 0;
-    if (inflateInit (&zstream) != Z_OK) {
-      GST_WARNING ("zlib initialization failed.");
-      ret = FALSE;
-      goto out;
-    }
-    zstream.next_in = (Bytef *) data;
-    zstream.avail_in = orig_size;
-    new_size = orig_size;
-    new_data = g_malloc (new_size);
-    zstream.avail_out = new_size;
-    zstream.next_out = (Bytef *) new_data;
-
-    do {
-      result = inflate (&zstream, Z_NO_FLUSH);
-      if (result != Z_OK && result != Z_STREAM_END) {
-        GST_WARNING ("zlib decompression failed.");
-        g_free (new_data);
-        inflateEnd (&zstream);
-        break;
-      }
-      new_size += 4000;
-      new_data = g_realloc (new_data, new_size);
-      zstream.next_out = (Bytef *) (new_data + zstream.total_out);
-      zstream.avail_out += 4000;
-    } while (zstream.avail_in != 0 && result != Z_STREAM_END);
-
-    if (result != Z_STREAM_END) {
-      ret = FALSE;
-      goto out;
-    } else {
-      new_size = zstream.total_out;
-      inflateEnd (&zstream);
-    }
-#else
-    GST_WARNING ("zlib encoded tracks not supported.");
-    ret = FALSE;
-    goto out;
-#endif
-  } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB) {
-#ifdef HAVE_BZ2
-    /* bzip2 encoded data */
-    bz_stream bzstream;
-    guint orig_size;
-    int result;
-
-    bzstream.bzalloc = NULL;
-    bzstream.bzfree = NULL;
-    bzstream.opaque = NULL;
-    orig_size = size;
-
-    if (BZ2_bzDecompressInit (&bzstream, 0, 0) != BZ_OK) {
-      GST_WARNING ("bzip2 initialization failed.");
-      ret = FALSE;
-      goto out;
-    }
-
-    bzstream.next_in = (char *) data;
-    bzstream.avail_in = orig_size;
-    new_size = orig_size;
-    new_data = g_malloc (new_size);
-    bzstream.avail_out = new_size;
-    bzstream.next_out = (char *) new_data;
-
-    do {
-      result = BZ2_bzDecompress (&bzstream);
-      if (result != BZ_OK && result != BZ_STREAM_END) {
-        GST_WARNING ("bzip2 decompression failed.");
-        g_free (new_data);
-        BZ2_bzDecompressEnd (&bzstream);
-        break;
-      }
-      new_size += 4000;
-      new_data = g_realloc (new_data, new_size);
-      bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32);
-      bzstream.avail_out += 4000;
-    } while (bzstream.avail_in != 0 && result != BZ_STREAM_END);
-
-    if (result != BZ_STREAM_END) {
-      ret = FALSE;
-      goto out;
-    } else {
-      new_size = bzstream.total_out_lo32;
-      BZ2_bzDecompressEnd (&bzstream);
-    }
-#else
-    GST_WARNING ("bzip2 encoded tracks not supported.");
-    ret = FALSE;
-    goto out;
-#endif
-  } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X) {
-    /* lzo encoded data */
-    int result;
-    int orig_size, out_size;
-
-    orig_size = size;
-    out_size = size;
-    new_size = size;
-    new_data = g_malloc (new_size);
-
-    do {
-      orig_size = size;
-      out_size = new_size;
-
-      result = lzo1x_decode (new_data, &out_size, data, &orig_size);
-
-      if (orig_size > 0) {
-        new_size += 4000;
-        new_data = g_realloc (new_data, new_size);
-      }
-    } while (orig_size > 0 && result == LZO_OUTPUT_FULL);
-
-    new_size -= out_size;
-
-    if (result != LZO_OUTPUT_FULL) {
-      GST_WARNING ("lzo decompression failed");
-      g_free (new_data);
-
-      ret = FALSE;
-      goto out;
-    }
-
-  } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP) {
-    /* header stripped encoded data */
-    if (enc->comp_settings_length > 0) {
-      new_data = g_malloc (size + enc->comp_settings_length);
-      new_size = size + enc->comp_settings_length;
-
-      memcpy (new_data, enc->comp_settings, enc->comp_settings_length);
-      memcpy (new_data + enc->comp_settings_length, data, size);
-    }
-  } else {
-    GST_ERROR ("invalid compression algorithm %d", algo);
-    ret = FALSE;
-  }
-
-out:
-
-  if (!ret) {
-    *data_out = NULL;
-    *size_out = 0;
-  } else {
-    *data_out = new_data;
-    *size_out = new_size;
-  }
-
-  return ret;
-}
-
-static gboolean
 gst_matroska_decode_data (GArray * encodings, guint8 ** data_out,
     guint * size_out, GstMatroskaTrackEncodingScope scope, gboolean free)
 {
@@ -1060,49 +862,6 @@ gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf)
 }
 
 static GstFlowReturn
-gst_matroska_decode_content_encodings (GArray * encodings)
-{
-  gint i;
-
-  if (encodings == NULL)
-    return GST_FLOW_OK;
-
-  for (i = 0; i < encodings->len; i++) {
-    GstMatroskaTrackEncoding *enc =
-        &g_array_index (encodings, GstMatroskaTrackEncoding, i);
-    guint8 *data = NULL;
-    guint size;
-
-    if ((enc->scope & GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING)
-        == 0)
-      continue;
-
-    /* Encryption not supported yet */
-    if (enc->type != 0)
-      return GST_FLOW_ERROR;
-
-    if (i + 1 >= encodings->len)
-      return GST_FLOW_ERROR;
-
-    if (enc->comp_settings_length == 0)
-      continue;
-
-    data = enc->comp_settings;
-    size = enc->comp_settings_length;
-
-    if (!gst_matroska_decompress_data (enc, &data, &size, enc->comp_algo))
-      return GST_FLOW_ERROR;
-
-    g_free (enc->comp_settings);
-
-    enc->comp_settings = data;
-    enc->comp_settings_length = size;
-  }
-
-  return GST_FLOW_OK;
-}
-
-static GstFlowReturn
 gst_matroska_demux_read_track_encodings (GstMatroskaDemux * demux,
     GstEbmlRead * ebml, GstMatroskaTrackContext * context)
 {
@@ -1151,9 +910,10 @@ gst_matroska_demux_tracknumber_unique (GstMatroskaDemux * demux, guint64 num)
 {
   gint i;
 
-  g_assert (demux->src->len == demux->num_streams);
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i);
+  g_assert (demux->common.src->len == demux->common.num_streams);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src,
+        i);
 
     if (context->num == num)
       return FALSE;
@@ -1187,8 +947,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
   /* allocate generic... if we know the type, we'll g_renew()
    * with the precise type */
   context = g_new0 (GstMatroskaTrackContext, 1);
-  g_ptr_array_add (demux->src, context);
-  context->index = demux->num_streams;
+  g_ptr_array_add (demux->common.src, context);
+  context->index = demux->common.num_streams;
   context->index_writer_id = -1;
   context->type = 0;            /* no type yet */
   context->default_duration = 0;
@@ -1200,8 +960,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
       GST_MATROSKA_TRACK_LACING;
   context->last_flow = GST_FLOW_OK;
   context->to_offset = G_MAXINT64;
-  demux->num_streams++;
-  g_assert (demux->src->len == demux->num_streams);
+  demux->common.num_streams++;
+  g_assert (demux->common.src->len == demux->common.num_streams);
 
   GST_DEBUG_OBJECT (demux, "Stream number %d", context->index);
 
@@ -1293,7 +1053,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
             context->type = 0;
             break;
         }
-        g_ptr_array_index (demux->src, demux->num_streams - 1) = context;
+        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
+            = context;
         break;
       }
 
@@ -1312,7 +1073,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
           break;
         }
         videocontext = (GstMatroskaTrackVideoContext *) context;
-        g_ptr_array_index (demux->src, demux->num_streams - 1) = context;
+        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
+            = context;
 
         while (ret == GST_FLOW_OK &&
             gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
@@ -1532,7 +1294,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
           break;
 
         audiocontext = (GstMatroskaTrackAudioContext *) context;
-        g_ptr_array_index (demux->src, demux->num_streams - 1) = context;
+        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
+            = context;
 
         while (ret == GST_FLOW_OK &&
             gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
@@ -1832,9 +1595,9 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
     if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
       GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header");
 
-    demux->num_streams--;
-    g_ptr_array_remove_index (demux->src, demux->num_streams);
-    g_assert (demux->src->len == demux->num_streams);
+    demux->common.num_streams--;
+    g_ptr_array_remove_index (demux->common.src, demux->common.num_streams);
+    g_assert (demux->common.src->len == demux->common.num_streams);
     if (context) {
       gst_matroska_track_free (context);
     }
@@ -2127,14 +1890,14 @@ gst_matroskademux_do_index_seek (GstMatroskaDemux * demux,
   GstMatroskaIndex *entry = NULL;
   GArray *index;
 
-  if (!demux->index || !demux->index->len)
+  if (!demux->common.index || !demux->common.index->len)
     return NULL;
 
   /* find entry just before or at the requested position */
   if (track && track->index_table)
     index = track->index_table;
   else
-    index = demux->index;
+    index = demux->common.index;
 
   entry =
       gst_util_array_binary_search (index->data, index->len,
@@ -2187,11 +1950,11 @@ gst_matroska_demux_send_event (GstMatroskaDemux * demux, GstEvent * event)
 
   is_newsegment = (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT);
 
-  g_assert (demux->src->len == demux->num_streams);
-  for (i = 0; i < demux->src->len; i++) {
+  g_assert (demux->common.src->len == demux->common.num_streams);
+  for (i = 0; i < demux->common.src->len; i++) {
     GstMatroskaTrackContext *stream;
 
-    stream = g_ptr_array_index (demux->src, i);
+    stream = g_ptr_array_index (demux->common.src, i);
     gst_event_ref (event);
     gst_pad_push_event (stream->pad, event);
     ret = TRUE;
@@ -2249,10 +2012,10 @@ gst_matroska_demux_get_seek_track (GstMatroskaDemux * demux,
   if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO)
     return track;
 
-  for (i = 0; i < demux->src->len; i++) {
+  for (i = 0; i < demux->common.src->len; i++) {
     GstMatroskaTrackContext *stream;
 
-    stream = g_ptr_array_index (demux->src, i);
+    stream = g_ptr_array_index (demux->common.src, i);
     if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table)
       track = stream;
   }
@@ -2269,9 +2032,10 @@ gst_matroska_demux_reset_streams (GstMatroskaDemux * demux, GstClockTime time,
 
   GST_DEBUG_OBJECT (demux, "resetting stream state");
 
-  g_assert (demux->src->len == demux->num_streams);
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i);
+  g_assert (demux->common.src->len == demux->common.num_streams);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src,
+        i);
     context->pos = time;
     context->set_discont = TRUE;
     context->eos = FALSE;
@@ -2297,10 +2061,10 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
 
   /* seek (relative to matroska segment) */
   /* position might be invalid; will error when streaming resumes ... */
-  demux->offset = entry->pos + demux->ebml_segment_start;
+  demux->offset = entry->pos + demux->common.ebml_segment_start;
 
   GST_DEBUG_OBJECT (demux, "Seeked to offset %" G_GUINT64_FORMAT ", block %d, "
-      "time %" GST_TIME_FORMAT, entry->pos + demux->ebml_segment_start,
+      "time %" GST_TIME_FORMAT, entry->pos + demux->common.ebml_segment_start,
       entry->block, GST_TIME_ARGS (entry->time));
 
   /* update the time */
@@ -2310,8 +2074,8 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
   demux->seek_first = TRUE;
   demux->last_stop_end = GST_CLOCK_TIME_NONE;
 
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *stream = g_ptr_array_index (demux->src, i);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *stream = g_ptr_array_index (demux->common.src, i);
 
     if (reset) {
       stream->to_offset = G_MAXINT64;
@@ -2458,7 +2222,7 @@ static GstMatroskaIndex *
 gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time)
 {
   GstMatroskaIndex *entry = NULL;
-  GstMatroskaDemuxState current_state;
+  GstMatroskaReadState current_state;
   GstClockTime otime, prev_cluster_time, current_cluster_time, cluster_time;
   gint64 opos, newpos, startpos = 0, current_offset;
   gint64 prev_cluster_offset = -1, current_cluster_offset, cluster_offset;
@@ -2476,18 +2240,18 @@ gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time)
   prev_cluster_time = GST_CLOCK_TIME_NONE;
 
   /* store some current state */
-  current_state = demux->state;
-  g_return_val_if_fail (current_state == GST_MATROSKA_DEMUX_STATE_DATA, NULL);
+  current_state = demux->common.state;
+  g_return_val_if_fail (current_state == GST_MATROSKA_READ_STATE_DATA, NULL);
 
   current_cluster_offset = demux->cluster_offset;
   current_cluster_time = demux->cluster_time;
   current_offset = demux->offset;
 
-  demux->state = GST_MATROSKA_DEMUX_STATE_SCANNING;
+  demux->common.state = GST_MATROSKA_READ_STATE_SCANNING;
 
   /* estimate using start and current position */
   GST_OBJECT_LOCK (demux);
-  opos = demux->offset - demux->ebml_segment_start;
+  opos = demux->offset - demux->common.ebml_segment_start;
   otime = demux->segment.last_stop;
   GST_OBJECT_UNLOCK (demux);
 
@@ -2500,7 +2264,7 @@ retry:
     newpos = 0;
   /* favour undershoot */
   newpos = newpos * 90 / 100;
-  newpos += demux->ebml_segment_start;
+  newpos += demux->common.ebml_segment_start;
 
   GST_DEBUG_OBJECT (demux,
       "estimated offset for %" GST_TIME_FORMAT ": %" G_GINT64_FORMAT,
@@ -2558,7 +2322,7 @@ retry:
     }
     if (demux->cluster_time != GST_CLOCK_TIME_NONE &&
         cluster_time == GST_CLOCK_TIME_NONE) {
-      cluster_time = demux->cluster_time * demux->time_scale;
+      cluster_time = demux->cluster_time * demux->common.time_scale;
       cluster_offset = demux->cluster_offset;
       GST_DEBUG_OBJECT (demux, "found cluster at offset %" G_GINT64_FORMAT
           " with time %" GST_TIME_FORMAT, cluster_offset,
@@ -2609,7 +2373,7 @@ retry:
 
   entry = g_new0 (GstMatroskaIndex, 1);
   entry->time = prev_cluster_time;
-  entry->pos = prev_cluster_offset - demux->ebml_segment_start;
+  entry->pos = prev_cluster_offset - demux->common.ebml_segment_start;
   GST_DEBUG_OBJECT (demux, "simulated index entry; time %" GST_TIME_FORMAT
       ", pos %" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->time), entry->pos);
 
@@ -2621,7 +2385,7 @@ exit:
   demux->cluster_offset = current_cluster_offset;
   demux->cluster_time = current_cluster_time;
   demux->offset = current_offset;
-  demux->state = current_state;
+  demux->common.state = current_state;
 
   return entry;
 }
@@ -2673,7 +2437,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
               seeksegment.last_stop, &demux->seek_index, &demux->seek_entry)) ==
       NULL) {
     /* pull mode without index can scan later on */
-    if (demux->index || demux->streaming) {
+    if (demux->common.index || demux->streaming) {
       GST_DEBUG_OBJECT (demux, "No matching seek entry in index");
       GST_OBJECT_UNLOCK (demux);
       return FALSE;
@@ -2687,7 +2451,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
     /* upstream takes care of flushing and all that
      * ... and newsegment event handling takes care of the rest */
     return perform_seek_to_offset (demux,
-        entry->pos + demux->ebml_segment_start);
+        entry->pos + demux->common.ebml_segment_start);
   }
 
   flush = !!(flags & GST_SEEK_FLAG_FLUSH);
@@ -2709,7 +2473,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
   GST_PAD_STREAM_LOCK (demux->sinkpad);
 
   /* pull mode without index can do some scanning */
-  if (!demux->streaming && !demux->index) {
+  if (!demux->streaming && !demux->common.index) {
     /* need to stop flushing upstream as we need it next */
     if (flush)
       gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
@@ -2840,7 +2604,7 @@ gst_matroska_demux_handle_seek_push (GstMatroskaDemux * demux, GstPad * pad,
   }
 
   /* check for having parsed index already */
-  if (!demux->index_parsed) {
+  if (!demux->common.index_parsed) {
     gboolean building_index;
     guint64 offset = 0;
 
@@ -2851,7 +2615,7 @@ gst_matroska_demux_handle_seek_push (GstMatroskaDemux * demux, GstPad * pad,
 
     GST_OBJECT_LOCK (demux);
     /* handle the seek event in the chain function */
-    demux->state = GST_MATROSKA_DEMUX_STATE_SEEK;
+    demux->common.state = GST_MATROSKA_READ_STATE_SEEK;
     /* no more seek can be issued until state reset to _DATA */
 
     /* copy the event */
@@ -2891,7 +2655,7 @@ gst_matroska_demux_handle_src_event (GstPad * pad, GstEvent * event)
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
       /* no seeking until we are (safely) ready */
-      if (demux->state != GST_MATROSKA_DEMUX_STATE_DATA) {
+      if (demux->common.state != GST_MATROSKA_READ_STATE_DATA) {
         GST_DEBUG_OBJECT (demux, "not ready for seeking yet");
         return FALSE;
       }
@@ -2958,8 +2722,8 @@ gst_matroska_demux_seek_to_previous_keyframe (GstMatroskaDemux * demux)
     goto exit;
   }
 
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *stream = g_ptr_array_index (demux->src, i);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *stream = g_ptr_array_index (demux->common.src, i);
 
     GST_DEBUG_OBJECT (demux, "segment start %" GST_TIME_FORMAT
         ", stream %d at %" GST_TIME_FORMAT,
@@ -2993,23 +2757,6 @@ exit:
   return ret;
 }
 
-/* skip unknown or alike element */
-static GstFlowReturn
-gst_matroska_demux_parse_skip (GstMatroskaDemux * demux, GstEbmlRead * ebml,
-    const gchar * parent_name, guint id)
-{
-  if (id == GST_EBML_ID_VOID) {
-    GST_DEBUG_OBJECT (demux, "Skipping EBML Void element");
-  } else if (id == GST_EBML_ID_CRC32) {
-    GST_DEBUG_OBJECT (demux, "Skipping EBML CRC32 element");
-  } else {
-    GST_WARNING_OBJECT (demux,
-        "Unknown %s subelement 0x%x - ignoring", parent_name, id);
-  }
-
-  return gst_ebml_read_skip (ebml);
-}
-
 static GstFlowReturn
 gst_matroska_demux_parse_header (GstMatroskaDemux * demux, GstEbmlRead * ebml)
 {
@@ -3121,7 +2868,8 @@ gst_matroska_demux_parse_header (GstMatroskaDemux * demux, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "EBML header", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "EBML header", id);
         if (ret != GST_FLOW_OK)
           return ret;
         break;
@@ -3190,7 +2938,8 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml)
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Track", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "Track", id);
         break;
     }
   }
@@ -3202,306 +2951,6 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml)
 }
 
 static GstFlowReturn
-gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux,
-    GstEbmlRead * ebml, guint * nentries)
-{
-  guint32 id;
-  GstFlowReturn ret;
-  GstMatroskaIndex idx;
-
-  idx.pos = (guint64) - 1;
-  idx.track = 0;
-  idx.time = GST_CLOCK_TIME_NONE;
-  idx.block = 1;
-
-  DEBUG_ELEMENT_START (demux, ebml, "CueTrackPositions");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (demux, ebml, "CueTrackPositions", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* track number */
-      case GST_MATROSKA_ID_CUETRACK:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num == 0) {
-          idx.track = 0;
-          GST_WARNING_OBJECT (demux, "Invalid CueTrack 0");
-          break;
-        }
-
-        GST_DEBUG_OBJECT (demux, "CueTrack: %" G_GUINT64_FORMAT, num);
-        idx.track = num;
-        break;
-      }
-
-        /* position in file */
-      case GST_MATROSKA_ID_CUECLUSTERPOSITION:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num > G_MAXINT64) {
-          GST_WARNING_OBJECT (demux, "CueClusterPosition %" G_GUINT64_FORMAT
-              " too large", num);
-          break;
-        }
-
-        idx.pos = num;
-        break;
-      }
-
-        /* number of block in the cluster */
-      case GST_MATROSKA_ID_CUEBLOCKNUMBER:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num == 0) {
-          GST_WARNING_OBJECT (demux, "Invalid CueBlockNumber 0");
-          break;
-        }
-
-        GST_DEBUG_OBJECT (demux, "CueBlockNumber: %" G_GUINT64_FORMAT, num);
-        idx.block = num;
-
-        /* mild sanity check, disregard strange cases ... */
-        if (idx.block > G_MAXUINT16) {
-          GST_DEBUG_OBJECT (demux, "... looks suspicious, ignoring");
-          idx.block = 1;
-        }
-        break;
-      }
-
-      default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "CueTrackPositions",
-            id);
-        break;
-
-      case GST_MATROSKA_ID_CUECODECSTATE:
-      case GST_MATROSKA_ID_CUEREFERENCE:
-        ret = gst_ebml_read_skip (ebml);
-        break;
-    }
-  }
-
-  DEBUG_ELEMENT_STOP (demux, ebml, "CueTrackPositions", ret);
-
-  if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
-      && idx.pos != (guint64) - 1 && idx.track > 0) {
-    g_array_append_val (demux->index, idx);
-    (*nentries)++;
-  } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) {
-    GST_DEBUG_OBJECT (demux, "CueTrackPositions without valid content");
-  }
-
-  return ret;
-}
-
-static GstFlowReturn
-gst_matroska_demux_parse_index_pointentry (GstMatroskaDemux * demux,
-    GstEbmlRead * ebml)
-{
-  guint32 id;
-  GstFlowReturn ret;
-  GstClockTime time = GST_CLOCK_TIME_NONE;
-  guint nentries = 0;
-
-  DEBUG_ELEMENT_START (demux, ebml, "CuePoint");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (demux, ebml, "CuePoint", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* one single index entry ('point') */
-      case GST_MATROSKA_ID_CUETIME:
-      {
-        if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
-          break;
-
-        GST_DEBUG_OBJECT (demux, "CueTime: %" G_GUINT64_FORMAT, time);
-        time = time * demux->time_scale;
-        break;
-      }
-
-        /* position in the file + track to which it belongs */
-      case GST_MATROSKA_ID_CUETRACKPOSITIONS:
-      {
-        if ((ret =
-                gst_matroska_demux_parse_index_cuetrack (demux, ebml,
-                    &nentries)) != GST_FLOW_OK)
-          break;
-        break;
-      }
-
-      default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "CuePoint", id);
-        break;
-    }
-  }
-
-  DEBUG_ELEMENT_STOP (demux, ebml, "CuePoint", ret);
-
-  if (nentries > 0) {
-    if (time == GST_CLOCK_TIME_NONE) {
-      GST_WARNING_OBJECT (demux, "CuePoint without valid time");
-      g_array_remove_range (demux->index, demux->index->len - nentries,
-          nentries);
-    } else {
-      gint i;
-
-      for (i = demux->index->len - nentries; i < demux->index->len; i++) {
-        GstMatroskaIndex *idx =
-            &g_array_index (demux->index, GstMatroskaIndex, i);
-
-        idx->time = time;
-        GST_DEBUG_OBJECT (demux, "Index entry: pos=%" G_GUINT64_FORMAT
-            ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
-            GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
-      }
-    }
-  } else {
-    GST_DEBUG_OBJECT (demux, "Empty CuePoint");
-  }
-
-  return ret;
-}
-
-static gint
-gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2)
-{
-  if (i1->time < i2->time)
-    return -1;
-  else if (i1->time > i2->time)
-    return 1;
-  else if (i1->block < i2->block)
-    return -1;
-  else if (i1->block > i2->block)
-    return 1;
-  else
-    return 0;
-}
-
-static GstFlowReturn
-gst_matroska_demux_parse_index (GstMatroskaDemux * demux, GstEbmlRead * ebml)
-{
-  guint32 id;
-  GstFlowReturn ret = GST_FLOW_OK;
-  guint i;
-
-  if (demux->index)
-    g_array_free (demux->index, TRUE);
-  demux->index =
-      g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
-
-  DEBUG_ELEMENT_START (demux, ebml, "Cues");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (demux, ebml, "Cues", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* one single index entry ('point') */
-      case GST_MATROSKA_ID_POINTENTRY:
-        ret = gst_matroska_demux_parse_index_pointentry (demux, ebml);
-        break;
-
-      default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Cues", id);
-        break;
-    }
-  }
-  DEBUG_ELEMENT_STOP (demux, ebml, "Cues", ret);
-
-  /* Sort index by time, smallest time first, for easier searching */
-  g_array_sort (demux->index, (GCompareFunc) gst_matroska_index_compare);
-
-  /* Now sort the track specific index entries into their own arrays */
-  for (i = 0; i < demux->index->len; i++) {
-    GstMatroskaIndex *idx = &g_array_index (demux->index, GstMatroskaIndex, i);
-    gint track_num;
-    GstMatroskaTrackContext *ctx;
-
-    if (demux->element_index) {
-      gint writer_id;
-
-      if (idx->track != 0 &&
-          (track_num =
-              gst_matroska_demux_stream_from_num (demux, idx->track)) != -1) {
-        ctx = g_ptr_array_index (demux->src, track_num);
-
-        if (ctx->index_writer_id == -1)
-          gst_index_get_writer_id (demux->element_index, GST_OBJECT (ctx->pad),
-              &ctx->index_writer_id);
-        writer_id = ctx->index_writer_id;
-      } else {
-        if (demux->element_index_writer_id == -1)
-          gst_index_get_writer_id (demux->element_index, GST_OBJECT (demux),
-              &demux->element_index_writer_id);
-        writer_id = demux->element_index_writer_id;
-      }
-
-      GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
-          G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time),
-          idx->pos, writer_id);
-      gst_index_add_association (demux->element_index, writer_id,
-          GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time,
-          GST_FORMAT_BYTES, idx->pos + demux->ebml_segment_start, NULL);
-    }
-
-    if (idx->track == 0)
-      continue;
-
-    track_num = gst_matroska_demux_stream_from_num (demux, idx->track);
-    if (track_num == -1)
-      continue;
-
-    ctx = g_ptr_array_index (demux->src, track_num);
-
-    if (ctx->index_table == NULL)
-      ctx->index_table =
-          g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
-
-    g_array_append_vals (ctx->index_table, idx, 1);
-  }
-
-  demux->index_parsed = TRUE;
-
-  /* sanity check; empty index normalizes to no index */
-  if (demux->index->len == 0) {
-    g_array_free (demux->index, TRUE);
-    demux->index = NULL;
-  }
-
-  return ret;
-}
-
-static GstFlowReturn
 gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml)
 {
   GstFlowReturn ret = GST_FLOW_OK;
@@ -3529,7 +2978,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml)
 
 
         GST_DEBUG_OBJECT (demux, "TimeCodeScale: %" G_GUINT64_FORMAT, num);
-        demux->time_scale = num;
+        demux->common.time_scale = num;
         break;
       }
 
@@ -3596,7 +3045,8 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "SegmentInfo", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "SegmentInfo", id);
         break;
 
         /* fall through */
@@ -3617,7 +3067,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml)
     GstClockTime dur_u;
 
     dur_u = gst_gdouble_to_guint64 (dur_f *
-        gst_guint64_to_gdouble (demux->time_scale));
+        gst_guint64_to_gdouble (demux->common.time_scale));
     if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
       gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME, dur_u);
   }
@@ -3692,7 +3142,8 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux,
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "SimpleTag", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "SimpleTag", id);
         break;
         /* fall-through */
 
@@ -3778,7 +3229,8 @@ gst_matroska_demux_parse_metadata_id_tag (GstMatroskaDemux * demux,
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Tag", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "Tag", id);
         break;
     }
   }
@@ -3834,7 +3286,8 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux * demux, GstEbmlRead * ebml)
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Tags", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "Tags", id);
         break;
         /* FIXME: Use to limit the tags to specific pads */
       case GST_MATROSKA_ID_TARGETS:
@@ -3917,7 +3370,8 @@ gst_matroska_demux_parse_attached_file (GstMatroskaDemux * demux,
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "AttachedFile", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "AttachedFile", id);
         break;
       case GST_MATROSKA_ID_FILEUID:
         ret = gst_ebml_read_skip (ebml);
@@ -4030,7 +3484,8 @@ gst_matroska_demux_parse_attachments (GstMatroskaDemux * demux,
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Attachments", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "Attachments", id);
         break;
     }
   }
@@ -4157,11 +3612,11 @@ gst_matroska_demux_sync_streams (GstMatroskaDemux * demux)
   GST_LOG_OBJECT (demux, "Sync to %" GST_TIME_FORMAT,
       GST_TIME_ARGS (demux->segment.last_stop));
 
-  g_assert (demux->num_streams == demux->src->len);
-  for (stream_nr = 0; stream_nr < demux->src->len; stream_nr++) {
+  g_assert (demux->common.num_streams == demux->common.src->len);
+  for (stream_nr = 0; stream_nr < demux->common.src->len; stream_nr++) {
     GstMatroskaTrackContext *context;
 
-    context = g_ptr_array_index (demux->src, stream_nr);
+    context = g_ptr_array_index (demux->common.src, stream_nr);
 
     GST_LOG_OBJECT (demux,
         "Checking for resync on stream %d (%" GST_TIME_FORMAT ")", stream_nr,
@@ -4769,14 +4224,15 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
         size -= n;
 
         /* fetch stream from num */
-        stream_num = gst_matroska_demux_stream_from_num (demux, num);
+        stream_num = gst_matroska_read_common_stream_from_num (&demux->common,
+            num);
         if (G_UNLIKELY (size < 3)) {
           GST_WARNING_OBJECT (demux, "Invalid size %u", size);
           /* non-fatal, try next block(group) */
           ret = GST_FLOW_OK;
           goto done;
         } else if (G_UNLIKELY (stream_num < 0 ||
-                stream_num >= demux->num_streams)) {
+                stream_num >= demux->common.num_streams)) {
           /* let's not give up on a stray invalid track number */
           GST_WARNING_OBJECT (demux,
               "Invalid stream %d for track number %" G_GUINT64_FORMAT
@@ -4784,7 +4240,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
           goto done;
         }
 
-        stream = g_ptr_array_index (demux->src, stream_num);
+        stream = g_ptr_array_index (demux->common.src, stream_num);
 
         /* time (relative to cluster time) */
         time = ((gint16) GST_READ_UINT16_BE (data));
@@ -4944,7 +4400,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "BlockGroup", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "BlockGroup", id);
         break;
 
       case GST_MATROSKA_ID_BLOCKVIRTUAL:
@@ -4971,7 +4428,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
     gint64 lace_time = 0;
     gboolean delta_unit;
 
-    stream = g_ptr_array_index (demux->src, stream_num);
+    stream = g_ptr_array_index (demux->common.src, stream_num);
 
     if (cluster_time != GST_CLOCK_TIME_NONE) {
       /* FIXME: What to do with negative timestamps? Give timestamp 0 or -1?
@@ -4980,11 +4437,11 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
         lace_time = 0;
       } else {
         if (stream->timecodescale == 1.0)
-          lace_time = (cluster_time + time) * demux->time_scale;
+          lace_time = (cluster_time + time) * demux->common.time_scale;
         else
           lace_time =
               gst_util_guint64_to_gdouble ((cluster_time + time) *
-              demux->time_scale) * stream->timecodescale;
+              demux->common.time_scale) * stream->timecodescale;
       }
     } else {
       lace_time = GST_CLOCK_TIME_NONE;
@@ -5008,11 +4465,12 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
 
     if (block_duration) {
       if (stream->timecodescale == 1.0)
-        duration = gst_util_uint64_scale (block_duration, demux->time_scale, 1);
+        duration = gst_util_uint64_scale (block_duration,
+            demux->common.time_scale, 1);
       else
         duration =
             gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble
-            (gst_util_uint64_scale (block_duration, demux->time_scale,
+            (gst_util_uint64_scale (block_duration, demux->common.time_scale,
                     1)) * stream->timecodescale);
     } else if (stream->default_duration) {
       duration = stream->default_duration * laces;
@@ -5214,16 +4672,16 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sub)),
           GST_TIME_ARGS (GST_BUFFER_DURATION (sub)));
 
-      if (demux->element_index) {
+      if (demux->common.element_index) {
         if (stream->index_writer_id == -1)
-          gst_index_get_writer_id (demux->element_index,
+          gst_index_get_writer_id (demux->common.element_index,
               GST_OBJECT (stream->pad), &stream->index_writer_id);
 
         GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
             G_GUINT64_FORMAT " for writer id %d",
             GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sub)), cluster_offset,
             stream->index_writer_id);
-        gst_index_add_association (demux->element_index,
+        gst_index_add_association (demux->common.element_index,
             stream->index_writer_id, GST_BUFFER_FLAG_IS_SET (sub,
                 GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : GST_ASSOCIATION_FLAG_KEY_UNIT,
             GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (sub), GST_FORMAT_BYTES,
@@ -5360,7 +4818,8 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "SeekHead", id);
         break;
     }
   }
@@ -5398,18 +4857,19 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
       }
 
       /* check for validity */
-      if (seek_pos + demux->ebml_segment_start + 12 >= length) {
+      if (seek_pos + demux->common.ebml_segment_start + 12 >= length) {
         GST_WARNING_OBJECT (demux,
             "SeekHead reference lies outside file!" " (%"
             G_GUINT64_FORMAT "+%" G_GUINT64_FORMAT "+12 >= %"
-            G_GUINT64_FORMAT ")", seek_pos, demux->ebml_segment_start, length);
+            G_GUINT64_FORMAT ")", seek_pos, demux->common.ebml_segment_start,
+            length);
         break;
       }
 
       /* only pick up index location when streaming */
       if (demux->streaming) {
         if (seek_id == GST_MATROSKA_ID_CUES) {
-          demux->index_offset = seek_pos + demux->ebml_segment_start;
+          demux->index_offset = seek_pos + demux->common.ebml_segment_start;
           GST_DEBUG_OBJECT (demux, "Cues located at offset %" G_GUINT64_FORMAT,
               demux->index_offset);
         }
@@ -5417,7 +4877,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
       }
 
       /* seek */
-      demux->offset = seek_pos + demux->ebml_segment_start;
+      demux->offset = seek_pos + demux->common.ebml_segment_start;
 
       /* check ID */
       if ((ret = gst_matroska_demux_peek_id_length_pull (demux, &id, &length,
@@ -5427,7 +4887,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
       if (id != seek_id) {
         GST_WARNING_OBJECT (demux,
             "We looked for ID=0x%x but got ID=0x%x (pos=%" G_GUINT64_FORMAT ")",
-            seek_id, id, seek_pos + demux->ebml_segment_start);
+            seek_id, id, seek_pos + demux->common.ebml_segment_start);
       } else {
         /* now parse */
         ret = gst_matroska_demux_parse_id (demux, id, length, needed);
@@ -5441,7 +4901,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
 
     case GST_MATROSKA_ID_CLUSTER:
     {
-      guint64 pos = seek_pos + demux->ebml_segment_start;
+      guint64 pos = seek_pos + demux->common.ebml_segment_start;
 
       GST_LOG_OBJECT (demux, "Cluster position");
       if (G_UNLIKELY (!demux->clusters))
@@ -5489,7 +4949,8 @@ gst_matroska_demux_parse_contents (GstMatroskaDemux * demux, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common,
+            ebml, "SeekHead", id);
         break;
     }
   }
@@ -5731,15 +5192,15 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
   if (G_LIKELY (length != G_MAXUINT64))
     read += needed;
 
-  switch (demux->state) {
-    case GST_MATROSKA_DEMUX_STATE_START:
+  switch (demux->common.state) {
+    case GST_MATROSKA_READ_STATE_START:
       switch (id) {
         case GST_EBML_ID_HEADER:
           GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
           ret = gst_matroska_demux_parse_header (demux, &ebml);
           if (ret != GST_FLOW_OK)
             goto parse_failed;
-          demux->state = GST_MATROSKA_DEMUX_STATE_SEGMENT;
+          demux->common.state = GST_MATROSKA_READ_STATE_SEGMENT;
           gst_matroska_demux_check_seekability (demux);
           break;
         default:
@@ -5747,7 +5208,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
           break;
       }
       break;
-    case GST_MATROSKA_DEMUX_STATE_SEGMENT:
+    case GST_MATROSKA_READ_STATE_SEGMENT:
       switch (id) {
         case GST_MATROSKA_ID_SEGMENT:
           /* eat segment prefix */
@@ -5757,8 +5218,8 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
               demux->offset);
           /* seeks are from the beginning of the segment,
            * after the segment ID/length */
-          demux->ebml_segment_start = demux->offset;
-          demux->state = GST_MATROSKA_DEMUX_STATE_HEADER;
+          demux->common.ebml_segment_start = demux->offset;
+          demux->common.state = GST_MATROSKA_READ_STATE_HEADER;
           break;
         default:
           GST_WARNING_OBJECT (demux,
@@ -5768,14 +5229,14 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
           break;
       }
       break;
-    case GST_MATROSKA_DEMUX_STATE_SCANNING:
+    case GST_MATROSKA_READ_STATE_SCANNING:
       if (id != GST_MATROSKA_ID_CLUSTER &&
           id != GST_MATROSKA_ID_CLUSTERTIMECODE)
         goto skip;
       /* fall-through */
-    case GST_MATROSKA_DEMUX_STATE_HEADER:
-    case GST_MATROSKA_DEMUX_STATE_DATA:
-    case GST_MATROSKA_DEMUX_STATE_SEEK:
+    case GST_MATROSKA_READ_STATE_HEADER:
+    case GST_MATROSKA_READ_STATE_DATA:
+    case GST_MATROSKA_READ_STATE_SEEK:
       switch (id) {
         case GST_MATROSKA_ID_SEGMENTINFO:
           if (!demux->segmentinfo_parsed) {
@@ -5804,8 +5265,9 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
                 goto no_tracks;
             }
           }
-          if (G_UNLIKELY (demux->state == GST_MATROSKA_DEMUX_STATE_HEADER)) {
-            demux->state = GST_MATROSKA_DEMUX_STATE_DATA;
+          if (G_UNLIKELY (demux->common.state
+                  == GST_MATROSKA_READ_STATE_HEADER)) {
+            demux->common.state = GST_MATROSKA_READ_STATE_DATA;
             demux->first_cluster_offset = demux->offset;
             GST_DEBUG_OBJECT (demux, "signaling no more pads");
             gst_element_no_more_pads (GST_ELEMENT (demux));
@@ -5840,16 +5302,17 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
             goto parse_failed;
           GST_DEBUG_OBJECT (demux, "ClusterTimeCode: %" G_GUINT64_FORMAT, num);
           demux->cluster_time = num;
-          if (demux->element_index) {
-            if (demux->element_index_writer_id == -1)
-              gst_index_get_writer_id (demux->element_index,
-                  GST_OBJECT (demux), &demux->element_index_writer_id);
+          if (demux->common.element_index) {
+            if (demux->common.element_index_writer_id == -1)
+              gst_index_get_writer_id (demux->common.element_index,
+                  GST_OBJECT (demux), &demux->common.element_index_writer_id);
             GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
                 G_GUINT64_FORMAT " for writer id %d",
                 GST_TIME_ARGS (demux->cluster_time), demux->cluster_offset,
-                demux->element_index_writer_id);
-            gst_index_add_association (demux->element_index,
-                demux->element_index_writer_id, GST_ASSOCIATION_FLAG_KEY_UNIT,
+                demux->common.element_index_writer_id);
+            gst_index_add_association (demux->common.element_index,
+                demux->common.element_index_writer_id,
+                GST_ASSOCIATION_FLAG_KEY_UNIT,
                 GST_FORMAT_TIME, demux->cluster_time,
                 GST_FORMAT_BYTES, demux->cluster_offset, NULL);
           }
@@ -5896,15 +5359,15 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
           ret = gst_matroska_demux_parse_contents (demux, &ebml);
           break;
         case GST_MATROSKA_ID_CUES:
-          if (demux->index_parsed) {
+          if (demux->common.index_parsed) {
             GST_READ_CHECK (gst_matroska_demux_flush (demux, read));
             break;
           }
           GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
-          ret = gst_matroska_demux_parse_index (demux, &ebml);
+          ret = gst_matroska_read_common_parse_index (&demux->common, &ebml);
           /* only push based; delayed index building */
           if (ret == GST_FLOW_OK
-              && demux->state == GST_MATROSKA_DEMUX_STATE_SEEK) {
+              && demux->common.state == GST_MATROSKA_READ_STATE_SEEK) {
             GstEvent *event;
 
             GST_OBJECT_LOCK (demux);
@@ -5918,7 +5381,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
               goto seek_failed;
             /* resume data handling, main thread clear to seek again */
             GST_OBJECT_LOCK (demux);
-            demux->state = GST_MATROSKA_DEMUX_STATE_DATA;
+            demux->common.state = GST_MATROSKA_READ_STATE_DATA;
             GST_OBJECT_UNLOCK (demux);
           }
           break;
@@ -5997,7 +5460,7 @@ gst_matroska_demux_loop (GstPad * pad)
   guint needed;
 
   /* If we have to close a segment, send a new segment to do this now */
-  if (G_LIKELY (demux->state == GST_MATROSKA_DEMUX_STATE_DATA)) {
+  if (G_LIKELY (demux->common.state == GST_MATROSKA_READ_STATE_DATA)) {
     if (G_UNLIKELY (demux->close_segment)) {
       gst_matroska_demux_send_event (demux, demux->close_segment);
       demux->close_segment = NULL;
@@ -6029,12 +5492,13 @@ gst_matroska_demux_loop (GstPad * pad)
     goto pause;
 
   /* check if we're at the end of a configured segment */
-  if (G_LIKELY (demux->src->len)) {
+  if (G_LIKELY (demux->common.src->len)) {
     guint i;
 
-    g_assert (demux->num_streams == demux->src->len);
-    for (i = 0; i < demux->src->len; i++) {
-      GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i);
+    g_assert (demux->common.num_streams == demux->common.src->len);
+    for (i = 0; i < demux->common.src->len; i++) {
+      GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src,
+          i);
       GST_DEBUG_OBJECT (context->pad, "pos %" GST_TIME_FORMAT,
           GST_TIME_ARGS (context->pos));
       if (context->eos == FALSE)
@@ -6234,7 +5698,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstEvent * event)
           "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
           &segment);
 
-      if (demux->state < GST_MATROSKA_DEMUX_STATE_DATA) {
+      if (demux->common.state < GST_MATROSKA_READ_STATE_DATA) {
         GST_DEBUG_OBJECT (demux, "still starting");
         goto exit;
       }
@@ -6270,11 +5734,11 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstEvent * event)
     }
     case GST_EVENT_EOS:
     {
-      if (demux->state != GST_MATROSKA_DEMUX_STATE_DATA) {
+      if (demux->common.state != GST_MATROSKA_READ_STATE_DATA) {
         gst_event_unref (event);
         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
             (NULL), ("got eos and didn't receive a complete header object"));
-      } else if (demux->num_streams == 0) {
+      } else if (demux->common.num_streams == 0) {
         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
             (NULL), ("got eos but no streams (yet)"));
       } else {
@@ -7093,11 +6557,12 @@ gst_matroska_demux_set_index (GstElement * element, GstIndex * index)
   GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
 
   GST_OBJECT_LOCK (demux);
-  if (demux->element_index)
-    gst_object_unref (demux->element_index);
-  demux->element_index = index ? gst_object_ref (index) : NULL;
+  if (demux->common.element_index)
+    gst_object_unref (demux->common.element_index);
+  demux->common.element_index = index ? gst_object_ref (index) : NULL;
   GST_OBJECT_UNLOCK (demux);
-  GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->element_index);
+  GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT,
+      demux->common.element_index);
 }
 
 static GstIndex *
@@ -7107,8 +6572,8 @@ gst_matroska_demux_get_index (GstElement * element)
   GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
 
   GST_OBJECT_LOCK (demux);
-  if (demux->element_index)
-    result = gst_object_ref (demux->element_index);
+  if (demux->common.element_index)
+    result = gst_object_ref (demux->common.element_index);
   GST_OBJECT_UNLOCK (demux);
 
   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
index a35a593..d0df0ac 100644 (file)
@@ -1,5 +1,6 @@
 /* GStreamer Matroska muxer/demuxer
  * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
  *
  * matroska-demux.h: matroska file/stream demuxer definition
  *
@@ -27,6 +28,7 @@
 
 #include "ebml-read.h"
 #include "matroska-ids.h"
+#include "matroska-read-common.h"
 
 G_BEGIN_DECLS
 
@@ -41,28 +43,16 @@ G_BEGIN_DECLS
 #define GST_IS_MATROSKA_DEMUX_CLASS(klass) \
   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_DEMUX))
 
-typedef enum {
-  GST_MATROSKA_DEMUX_STATE_START,
-  GST_MATROSKA_DEMUX_STATE_SEGMENT,
-  GST_MATROSKA_DEMUX_STATE_HEADER,
-  GST_MATROSKA_DEMUX_STATE_DATA,
-  GST_MATROSKA_DEMUX_STATE_SEEK,
-  GST_MATROSKA_DEMUX_STATE_SCANNING
-} GstMatroskaDemuxState;
-
 typedef struct _GstMatroskaDemux {
   GstElement              parent;
 
   /* < private > */
 
-  GstIndex                *element_index;
-  gint                     element_index_writer_id;
+  GstMatroskaReadCommon    common;
 
   /* pads */
   GstPad                  *sinkpad;
-  GPtrArray               *src;
   GstClock                *clock;
-  guint                    num_streams;
   guint                    num_v_streams;
   guint                    num_a_streams;
   guint                    num_t_streams;
@@ -74,30 +64,20 @@ typedef struct _GstMatroskaDemux {
 
   /* state */
   gboolean                 streaming;
-  GstMatroskaDemuxState    state;
   guint                    level_up;
   guint64                  seek_block;
   gboolean                 seek_first;
 
   /* did we parse cues/tracks/segmentinfo already? */
-  gboolean                 index_parsed;
   gboolean                 tracks_parsed;
   gboolean                 segmentinfo_parsed;
   gboolean                 attachments_parsed;
   GList                   *tags_parsed;
   GList                   *seek_parsed;
 
-  /* start-of-segment */
-  guint64                  ebml_segment_start;
-
-  /* a cue (index) table */
-  GArray                  *index;
   /* cluster positions (optional) */
   GArray                  *clusters;
 
-  /* timescale in the file */
-  guint64                  time_scale;
-
   /* keeping track of playback position */
   GstSegment               segment;
   gboolean                 segment_running;
index 7d48849..1b4f724 100644 (file)
@@ -2,6 +2,7 @@
  * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
  * (c) 2006 Tim-Philipp Müller <tim centricular net>
  * (c) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
  *
  * matroska-parse.c: matroska file/stream parser
  *
 
 #include <gst/base/gsttypefindhelper.h>
 
-#ifdef HAVE_ZLIB
-#include <zlib.h>
-#endif
-
-#ifdef HAVE_BZ2
-#include <bzlib.h>
-#endif
-
 #include <gst/pbutils/pbutils.h>
 
-#include "lzo.h"
-
 #include "matroska-parse.h"
 #include "matroska-ids.h"
 
@@ -170,9 +161,9 @@ gst_matroska_parse_finalize (GObject * object)
 {
   GstMatroskaParse *parse = GST_MATROSKA_PARSE (object);
 
-  if (parse->src) {
-    g_ptr_array_free (parse->src, TRUE);
-    parse->src = NULL;
+  if (parse->common.src) {
+    g_ptr_array_free (parse->common.src, TRUE);
+    parse->common.src = NULL;
   }
 
   if (parse->global_tags) {
@@ -232,11 +223,11 @@ gst_matroska_parse_init (GstMatroskaParse * parse,
   gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
 
   /* initial stream no. */
-  parse->src = NULL;
+  parse->common.src = NULL;
 
   parse->writing_app = NULL;
   parse->muxing_app = NULL;
-  parse->index = NULL;
+  parse->common.index = NULL;
   parse->global_tags = NULL;
 
   parse->adapter = gst_adapter_new ();
@@ -292,22 +283,23 @@ gst_matroska_parse_reset (GstElement * element)
   GST_DEBUG_OBJECT (parse, "Resetting state");
 
   /* reset input */
-  parse->state = GST_MATROSKA_PARSE_STATE_START;
+  parse->common.state = GST_MATROSKA_READ_STATE_START;
 
   /* clean up existing streams */
-  if (parse->src) {
-    g_assert (parse->src->len == parse->num_streams);
-    for (i = 0; i < parse->src->len; i++) {
-      GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
+  if (parse->common.src) {
+    g_assert (parse->common.src->len == parse->common.num_streams);
+    for (i = 0; i < parse->common.src->len; i++) {
+      GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src,
+          i);
 
       gst_caps_replace (&context->caps, NULL);
       gst_matroska_track_free (context);
     }
-    g_ptr_array_free (parse->src, TRUE);
+    g_ptr_array_free (parse->common.src, TRUE);
   }
-  parse->src = g_ptr_array_new ();
+  parse->common.src = g_ptr_array_new ();
 
-  parse->num_streams = 0;
+  parse->common.num_streams = 0;
   parse->num_a_streams = 0;
   parse->num_t_streams = 0;
   parse->num_v_streams = 0;
@@ -319,17 +311,17 @@ gst_matroska_parse_reset (GstElement * element)
   parse->muxing_app = NULL;
 
   /* reset indexes */
-  if (parse->index) {
-    g_array_free (parse->index, TRUE);
-    parse->index = NULL;
+  if (parse->common.index) {
+    g_array_free (parse->common.index, TRUE);
+    parse->common.index = NULL;
   }
 
   /* reset timers */
   parse->clock = NULL;
-  parse->time_scale = 1000000;
+  parse->common.time_scale = 1000000;
   parse->created = G_MININT64;
 
-  parse->index_parsed = FALSE;
+  parse->common.index_parsed = FALSE;
   parse->tracks_parsed = FALSE;
   parse->segmentinfo_parsed = FALSE;
   parse->attachments_parsed = FALSE;
@@ -374,11 +366,11 @@ gst_matroska_parse_reset (GstElement * element)
     parse->new_segment = NULL;
   }
 
-  if (parse->element_index) {
-    gst_object_unref (parse->element_index);
-    parse->element_index = NULL;
+  if (parse->common.element_index) {
+    gst_object_unref (parse->common.element_index);
+    parse->common.element_index = NULL;
   }
-  parse->element_index_writer_id = -1;
+  parse->common.element_index_writer_id = -1;
 
   if (parse->global_tags) {
     gst_tag_list_free (parse->global_tags);
@@ -508,27 +500,6 @@ gst_matroska_parse_get_length (GstMatroskaParse * parse)
 }
 
 static gint
-gst_matroska_parse_stream_from_num (GstMatroskaParse * parse, guint track_num)
-{
-  guint n;
-
-  g_assert (parse->src->len == parse->num_streams);
-  for (n = 0; n < parse->src->len; n++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, n);
-
-    if (context->num == track_num) {
-      return n;
-    }
-  }
-
-  if (n == parse->num_streams)
-    GST_WARNING_OBJECT (parse,
-        "Failed to find corresponding pad for tracknum %d", track_num);
-
-  return -1;
-}
-
-static gint
 gst_matroska_parse_encoding_cmp (GstMatroskaTrackEncoding * a,
     GstMatroskaTrackEncoding * b)
 {
@@ -718,176 +689,6 @@ gst_matroska_parse_read_track_encoding (GstMatroskaParse * parse,
 }
 
 static gboolean
-gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
-    guint8 ** data_out, guint * size_out,
-    GstMatroskaTrackCompressionAlgorithm algo)
-{
-  guint8 *new_data = NULL;
-  guint new_size = 0;
-  guint8 *data = *data_out;
-  guint size = *size_out;
-  gboolean ret = TRUE;
-
-  if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB) {
-#ifdef HAVE_ZLIB
-    /* zlib encoded data */
-    z_stream zstream;
-    guint orig_size;
-    int result;
-
-    orig_size = size;
-    zstream.zalloc = (alloc_func) 0;
-    zstream.zfree = (free_func) 0;
-    zstream.opaque = (voidpf) 0;
-    if (inflateInit (&zstream) != Z_OK) {
-      GST_WARNING ("zlib initialization failed.");
-      ret = FALSE;
-      goto out;
-    }
-    zstream.next_in = (Bytef *) data;
-    zstream.avail_in = orig_size;
-    new_size = orig_size;
-    new_data = g_malloc (new_size);
-    zstream.avail_out = new_size;
-    zstream.next_out = (Bytef *) new_data;
-
-    do {
-      result = inflate (&zstream, Z_NO_FLUSH);
-      if (result != Z_OK && result != Z_STREAM_END) {
-        GST_WARNING ("zlib decompression failed.");
-        g_free (new_data);
-        inflateEnd (&zstream);
-        break;
-      }
-      new_size += 4000;
-      new_data = g_realloc (new_data, new_size);
-      zstream.next_out = (Bytef *) (new_data + zstream.total_out);
-      zstream.avail_out += 4000;
-    } while (zstream.avail_in != 0 && result != Z_STREAM_END);
-
-    if (result != Z_STREAM_END) {
-      ret = FALSE;
-      goto out;
-    } else {
-      new_size = zstream.total_out;
-      inflateEnd (&zstream);
-    }
-#else
-    GST_WARNING ("zlib encoded tracks not supported.");
-    ret = FALSE;
-    goto out;
-#endif
-  } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB) {
-#ifdef HAVE_BZ2
-    /* bzip2 encoded data */
-    bz_stream bzstream;
-    guint orig_size;
-    int result;
-
-    bzstream.bzalloc = NULL;
-    bzstream.bzfree = NULL;
-    bzstream.opaque = NULL;
-    orig_size = size;
-
-    if (BZ2_bzDecompressInit (&bzstream, 0, 0) != BZ_OK) {
-      GST_WARNING ("bzip2 initialization failed.");
-      ret = FALSE;
-      goto out;
-    }
-
-    bzstream.next_in = (char *) data;
-    bzstream.avail_in = orig_size;
-    new_size = orig_size;
-    new_data = g_malloc (new_size);
-    bzstream.avail_out = new_size;
-    bzstream.next_out = (char *) new_data;
-
-    do {
-      result = BZ2_bzDecompress (&bzstream);
-      if (result != BZ_OK && result != BZ_STREAM_END) {
-        GST_WARNING ("bzip2 decompression failed.");
-        g_free (new_data);
-        BZ2_bzDecompressEnd (&bzstream);
-        break;
-      }
-      new_size += 4000;
-      new_data = g_realloc (new_data, new_size);
-      bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32);
-      bzstream.avail_out += 4000;
-    } while (bzstream.avail_in != 0 && result != BZ_STREAM_END);
-
-    if (result != BZ_STREAM_END) {
-      ret = FALSE;
-      goto out;
-    } else {
-      new_size = bzstream.total_out_lo32;
-      BZ2_bzDecompressEnd (&bzstream);
-    }
-#else
-    GST_WARNING ("bzip2 encoded tracks not supported.");
-    ret = FALSE;
-    goto out;
-#endif
-  } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X) {
-    /* lzo encoded data */
-    int result;
-    int orig_size, out_size;
-
-    orig_size = size;
-    out_size = size;
-    new_size = size;
-    new_data = g_malloc (new_size);
-
-    do {
-      orig_size = size;
-      out_size = new_size;
-
-      result = lzo1x_decode (new_data, &out_size, data, &orig_size);
-
-      if (orig_size > 0) {
-        new_size += 4000;
-        new_data = g_realloc (new_data, new_size);
-      }
-    } while (orig_size > 0 && result == LZO_OUTPUT_FULL);
-
-    new_size -= out_size;
-
-    if (result != LZO_OUTPUT_FULL) {
-      GST_WARNING ("lzo decompression failed");
-      g_free (new_data);
-
-      ret = FALSE;
-      goto out;
-    }
-
-  } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP) {
-    /* header stripped encoded data */
-    if (enc->comp_settings_length > 0) {
-      new_data = g_malloc (size + enc->comp_settings_length);
-      new_size = size + enc->comp_settings_length;
-
-      memcpy (new_data, enc->comp_settings, enc->comp_settings_length);
-      memcpy (new_data + enc->comp_settings_length, data, size);
-    }
-  } else {
-    GST_ERROR ("invalid compression algorithm %d", algo);
-    ret = FALSE;
-  }
-
-out:
-
-  if (!ret) {
-    *data_out = NULL;
-    *size_out = 0;
-  } else {
-    *data_out = new_data;
-    *size_out = new_size;
-  }
-
-  return ret;
-}
-
-static gboolean
 gst_matroska_decode_data (GArray * encodings, guint8 ** data_out,
     guint * size_out, GstMatroskaTrackEncodingScope scope, gboolean free)
 {
@@ -950,49 +751,6 @@ gst_matroska_decode_data (GArray * encodings, guint8 ** data_out,
 }
 
 static GstFlowReturn
-gst_matroska_decode_content_encodings (GArray * encodings)
-{
-  gint i;
-
-  if (encodings == NULL)
-    return GST_FLOW_OK;
-
-  for (i = 0; i < encodings->len; i++) {
-    GstMatroskaTrackEncoding *enc =
-        &g_array_index (encodings, GstMatroskaTrackEncoding, i);
-    guint8 *data = NULL;
-    guint size;
-
-    if ((enc->scope & GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING)
-        == 0)
-      continue;
-
-    /* Encryption not supported yet */
-    if (enc->type != 0)
-      return GST_FLOW_ERROR;
-
-    if (i + 1 >= encodings->len)
-      return GST_FLOW_ERROR;
-
-    if (enc->comp_settings_length == 0)
-      continue;
-
-    data = enc->comp_settings;
-    size = enc->comp_settings_length;
-
-    if (!gst_matroska_decompress_data (enc, &data, &size, enc->comp_algo))
-      return GST_FLOW_ERROR;
-
-    g_free (enc->comp_settings);
-
-    enc->comp_settings = data;
-    enc->comp_settings_length = size;
-  }
-
-  return GST_FLOW_OK;
-}
-
-static GstFlowReturn
 gst_matroska_parse_read_track_encodings (GstMatroskaParse * parse,
     GstEbmlRead * ebml, GstMatroskaTrackContext * context)
 {
@@ -1041,9 +799,10 @@ gst_matroska_parse_tracknumber_unique (GstMatroskaParse * parse, guint64 num)
 {
   gint i;
 
-  g_assert (parse->src->len == parse->num_streams);
-  for (i = 0; i < parse->src->len; i++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
+  g_assert (parse->common.src->len == parse->common.num_streams);
+  for (i = 0; i < parse->common.src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src,
+        i);
 
     if (context->num == num)
       return FALSE;
@@ -1070,8 +829,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
   /* allocate generic... if we know the type, we'll g_renew()
    * with the precise type */
   context = g_new0 (GstMatroskaTrackContext, 1);
-  g_ptr_array_add (parse->src, context);
-  context->index = parse->num_streams;
+  g_ptr_array_add (parse->common.src, context);
+  context->index = parse->common.num_streams;
   context->index_writer_id = -1;
   context->type = 0;            /* no type yet */
   context->default_duration = 0;
@@ -1083,8 +842,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
       GST_MATROSKA_TRACK_LACING;
   context->last_flow = GST_FLOW_OK;
   context->to_offset = G_MAXINT64;
-  parse->num_streams++;
-  g_assert (parse->src->len == parse->num_streams);
+  parse->common.num_streams++;
+  g_assert (parse->common.src->len == parse->common.num_streams);
 
   GST_DEBUG_OBJECT (parse, "Stream number %d", context->index);
 
@@ -1176,7 +935,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
             context->type = 0;
             break;
         }
-        g_ptr_array_index (parse->src, parse->num_streams - 1) = context;
+        g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
+            = context;
         break;
       }
 
@@ -1195,7 +955,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
           break;
         }
         videocontext = (GstMatroskaTrackVideoContext *) context;
-        g_ptr_array_index (parse->src, parse->num_streams - 1) = context;
+        g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
+            = context;
 
         while (ret == GST_FLOW_OK &&
             gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
@@ -1415,7 +1176,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
           break;
 
         audiocontext = (GstMatroskaTrackAudioContext *) context;
-        g_ptr_array_index (parse->src, parse->num_streams - 1) = context;
+        g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
+            = context;
 
         while (ret == GST_FLOW_OK &&
             gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
@@ -1715,9 +1477,9 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
     if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
       GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header");
 
-    parse->num_streams--;
-    g_ptr_array_remove_index (parse->src, parse->num_streams);
-    g_assert (parse->src->len == parse->num_streams);
+    parse->common.num_streams--;
+    g_ptr_array_remove_index (parse->common.src, parse->common.num_streams);
+    g_assert (parse->common.src->len == parse->common.num_streams);
     if (context) {
       gst_matroska_track_free (context);
     }
@@ -1880,14 +1642,14 @@ gst_matroskaparse_do_index_seek (GstMatroskaParse * parse,
   GstMatroskaIndex *entry = NULL;
   GArray *index;
 
-  if (!parse->index || !parse->index->len)
+  if (!parse->common.index || !parse->common.index->len)
     return NULL;
 
   /* find entry just before or at the requested position */
   if (track && track->index_table)
     index = track->index_table;
   else
-    index = parse->index;
+    index = parse->common.index;
 
   entry =
       gst_util_array_binary_search (index->data, index->len,
@@ -1970,10 +1732,10 @@ gst_matroska_parse_get_seek_track (GstMatroskaParse * parse,
   if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO)
     return track;
 
-  for (i = 0; i < parse->src->len; i++) {
+  for (i = 0; i < parse->common.src->len; i++) {
     GstMatroskaTrackContext *stream;
 
-    stream = g_ptr_array_index (parse->src, i);
+    stream = g_ptr_array_index (parse->common.src, i);
     if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table)
       track = stream;
   }
@@ -1989,9 +1751,10 @@ gst_matroska_parse_reset_streams (GstMatroskaParse * parse, GstClockTime time,
 
   GST_DEBUG_OBJECT (parse, "resetting stream state");
 
-  g_assert (parse->src->len == parse->num_streams);
-  for (i = 0; i < parse->src->len; i++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
+  g_assert (parse->common.src->len == parse->common.num_streams);
+  for (i = 0; i < parse->common.src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src,
+        i);
     context->pos = time;
     context->set_discont = TRUE;
     context->eos = FALSE;
@@ -2153,7 +1916,8 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
   /* need to seek to cluster start to pick up cluster time */
   /* upstream takes care of flushing and all that
    * ... and newsegment event handling takes care of the rest */
-  return perform_seek_to_offset (parse, entry->pos + parse->ebml_segment_start);
+  return perform_seek_to_offset (parse, entry->pos
+      + parse->common.ebml_segment_start);
 }
 
 /*
@@ -2198,7 +1962,7 @@ gst_matroska_parse_handle_seek_push (GstMatroskaParse * parse, GstPad * pad,
   }
 
   /* check for having parsed index already */
-  if (!parse->index_parsed) {
+  if (!parse->common.index_parsed) {
     gboolean building_index;
     guint64 offset = 0;
 
@@ -2209,7 +1973,7 @@ gst_matroska_parse_handle_seek_push (GstMatroskaParse * parse, GstPad * pad,
 
     GST_OBJECT_LOCK (parse);
     /* handle the seek event in the chain function */
-    parse->state = GST_MATROSKA_PARSE_STATE_SEEK;
+    parse->common.state = GST_MATROSKA_READ_STATE_SEEK;
     /* no more seek can be issued until state reset to _DATA */
 
     /* copy the event */
@@ -2249,7 +2013,7 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event)
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
       /* no seeking until we are (safely) ready */
-      if (parse->state != GST_MATROSKA_PARSE_STATE_DATA) {
+      if (parse->common.state != GST_MATROSKA_READ_STATE_DATA) {
         GST_DEBUG_OBJECT (parse, "not ready for seeking yet");
         return FALSE;
       }
@@ -2295,24 +2059,6 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event)
   return res;
 }
 
-
-/* skip unknown or alike element */
-static GstFlowReturn
-gst_matroska_parse_parse_skip (GstMatroskaParse * parse, GstEbmlRead * ebml,
-    const gchar * parent_name, guint id)
-{
-  if (id == GST_EBML_ID_VOID) {
-    GST_DEBUG_OBJECT (parse, "Skipping EBML Void element");
-  } else if (id == GST_EBML_ID_CRC32) {
-    GST_DEBUG_OBJECT (parse, "Skipping EBML CRC32 element");
-  } else {
-    GST_WARNING_OBJECT (parse,
-        "Unknown %s subelement 0x%x - ignoring", parent_name, id);
-  }
-
-  return gst_ebml_read_skip (ebml);
-}
-
 static GstFlowReturn
 gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml)
 {
@@ -2424,7 +2170,8 @@ gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "EBML header", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "EBML header", id);
         if (ret != GST_FLOW_OK)
           return ret;
         break;
@@ -2493,7 +2240,8 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml)
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Track", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "Track", id);
         break;
     }
   }
@@ -2505,306 +2253,6 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml)
 }
 
 static GstFlowReturn
-gst_matroska_parse_parse_index_cuetrack (GstMatroskaParse * parse,
-    GstEbmlRead * ebml, guint * nentries)
-{
-  guint32 id;
-  GstFlowReturn ret;
-  GstMatroskaIndex idx;
-
-  idx.pos = (guint64) - 1;
-  idx.track = 0;
-  idx.time = GST_CLOCK_TIME_NONE;
-  idx.block = 1;
-
-  DEBUG_ELEMENT_START (parse, ebml, "CueTrackPositions");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* track number */
-      case GST_MATROSKA_ID_CUETRACK:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num == 0) {
-          idx.track = 0;
-          GST_WARNING_OBJECT (parse, "Invalid CueTrack 0");
-          break;
-        }
-
-        GST_DEBUG_OBJECT (parse, "CueTrack: %" G_GUINT64_FORMAT, num);
-        idx.track = num;
-        break;
-      }
-
-        /* position in file */
-      case GST_MATROSKA_ID_CUECLUSTERPOSITION:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num > G_MAXINT64) {
-          GST_WARNING_OBJECT (parse, "CueClusterPosition %" G_GUINT64_FORMAT
-              " too large", num);
-          break;
-        }
-
-        idx.pos = num;
-        break;
-      }
-
-        /* number of block in the cluster */
-      case GST_MATROSKA_ID_CUEBLOCKNUMBER:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num == 0) {
-          GST_WARNING_OBJECT (parse, "Invalid CueBlockNumber 0");
-          break;
-        }
-
-        GST_DEBUG_OBJECT (parse, "CueBlockNumber: %" G_GUINT64_FORMAT, num);
-        idx.block = num;
-
-        /* mild sanity check, disregard strange cases ... */
-        if (idx.block > G_MAXUINT16) {
-          GST_DEBUG_OBJECT (parse, "... looks suspicious, ignoring");
-          idx.block = 1;
-        }
-        break;
-      }
-
-      default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "CueTrackPositions",
-            id);
-        break;
-
-      case GST_MATROSKA_ID_CUECODECSTATE:
-      case GST_MATROSKA_ID_CUEREFERENCE:
-        ret = gst_ebml_read_skip (ebml);
-        break;
-    }
-  }
-
-  DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret);
-
-  if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
-      && idx.pos != (guint64) - 1 && idx.track > 0) {
-    g_array_append_val (parse->index, idx);
-    (*nentries)++;
-  } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) {
-    GST_DEBUG_OBJECT (parse, "CueTrackPositions without valid content");
-  }
-
-  return ret;
-}
-
-static GstFlowReturn
-gst_matroska_parse_parse_index_pointentry (GstMatroskaParse * parse,
-    GstEbmlRead * ebml)
-{
-  guint32 id;
-  GstFlowReturn ret;
-  GstClockTime time = GST_CLOCK_TIME_NONE;
-  guint nentries = 0;
-
-  DEBUG_ELEMENT_START (parse, ebml, "CuePoint");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* one single index entry ('point') */
-      case GST_MATROSKA_ID_CUETIME:
-      {
-        if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
-          break;
-
-        GST_DEBUG_OBJECT (parse, "CueTime: %" G_GUINT64_FORMAT, time);
-        time = time * parse->time_scale;
-        break;
-      }
-
-        /* position in the file + track to which it belongs */
-      case GST_MATROSKA_ID_CUETRACKPOSITIONS:
-      {
-        if ((ret =
-                gst_matroska_parse_parse_index_cuetrack (parse, ebml,
-                    &nentries)) != GST_FLOW_OK)
-          break;
-        break;
-      }
-
-      default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "CuePoint", id);
-        break;
-    }
-  }
-
-  DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret);
-
-  if (nentries > 0) {
-    if (time == GST_CLOCK_TIME_NONE) {
-      GST_WARNING_OBJECT (parse, "CuePoint without valid time");
-      g_array_remove_range (parse->index, parse->index->len - nentries,
-          nentries);
-    } else {
-      gint i;
-
-      for (i = parse->index->len - nentries; i < parse->index->len; i++) {
-        GstMatroskaIndex *idx =
-            &g_array_index (parse->index, GstMatroskaIndex, i);
-
-        idx->time = time;
-        GST_DEBUG_OBJECT (parse, "Index entry: pos=%" G_GUINT64_FORMAT
-            ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
-            GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
-      }
-    }
-  } else {
-    GST_DEBUG_OBJECT (parse, "Empty CuePoint");
-  }
-
-  return ret;
-}
-
-static gint
-gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2)
-{
-  if (i1->time < i2->time)
-    return -1;
-  else if (i1->time > i2->time)
-    return 1;
-  else if (i1->block < i2->block)
-    return -1;
-  else if (i1->block > i2->block)
-    return 1;
-  else
-    return 0;
-}
-
-static GstFlowReturn
-gst_matroska_parse_parse_index (GstMatroskaParse * parse, GstEbmlRead * ebml)
-{
-  guint32 id;
-  GstFlowReturn ret = GST_FLOW_OK;
-  guint i;
-
-  if (parse->index)
-    g_array_free (parse->index, TRUE);
-  parse->index =
-      g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
-
-  DEBUG_ELEMENT_START (parse, ebml, "Cues");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* one single index entry ('point') */
-      case GST_MATROSKA_ID_POINTENTRY:
-        ret = gst_matroska_parse_parse_index_pointentry (parse, ebml);
-        break;
-
-      default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Cues", id);
-        break;
-    }
-  }
-  DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret);
-
-  /* Sort index by time, smallest time first, for easier searching */
-  g_array_sort (parse->index, (GCompareFunc) gst_matroska_index_compare);
-
-  /* Now sort the track specific index entries into their own arrays */
-  for (i = 0; i < parse->index->len; i++) {
-    GstMatroskaIndex *idx = &g_array_index (parse->index, GstMatroskaIndex, i);
-    gint track_num;
-    GstMatroskaTrackContext *ctx;
-
-    if (parse->element_index) {
-      gint writer_id;
-
-      if (idx->track != 0 &&
-          (track_num =
-              gst_matroska_parse_stream_from_num (parse, idx->track)) != -1) {
-        ctx = g_ptr_array_index (parse->src, track_num);
-
-        if (ctx->index_writer_id == -1)
-          gst_index_get_writer_id (parse->element_index, GST_OBJECT (ctx->pad),
-              &ctx->index_writer_id);
-        writer_id = ctx->index_writer_id;
-      } else {
-        if (parse->element_index_writer_id == -1)
-          gst_index_get_writer_id (parse->element_index, GST_OBJECT (parse),
-              &parse->element_index_writer_id);
-        writer_id = parse->element_index_writer_id;
-      }
-
-      GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %"
-          G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time),
-          idx->pos, writer_id);
-      gst_index_add_association (parse->element_index, writer_id,
-          GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time,
-          GST_FORMAT_BYTES, idx->pos + parse->ebml_segment_start, NULL);
-    }
-
-    if (idx->track == 0)
-      continue;
-
-    track_num = gst_matroska_parse_stream_from_num (parse, idx->track);
-    if (track_num == -1)
-      continue;
-
-    ctx = g_ptr_array_index (parse->src, track_num);
-
-    if (ctx->index_table == NULL)
-      ctx->index_table =
-          g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
-
-    g_array_append_vals (ctx->index_table, idx, 1);
-  }
-
-  parse->index_parsed = TRUE;
-
-  /* sanity check; empty index normalizes to no index */
-  if (parse->index->len == 0) {
-    g_array_free (parse->index, TRUE);
-    parse->index = NULL;
-  }
-
-  return ret;
-}
-
-static GstFlowReturn
 gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
 {
   GstFlowReturn ret = GST_FLOW_OK;
@@ -2832,7 +2280,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
 
 
         GST_DEBUG_OBJECT (parse, "TimeCodeScale: %" G_GUINT64_FORMAT, num);
-        parse->time_scale = num;
+        parse->common.time_scale = num;
         break;
       }
 
@@ -2899,7 +2347,8 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "SegmentInfo", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SegmentInfo", id);
         break;
 
         /* fall through */
@@ -2920,7 +2369,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
     GstClockTime dur_u;
 
     dur_u = gst_gdouble_to_guint64 (dur_f *
-        gst_guint64_to_gdouble (parse->time_scale));
+        gst_guint64_to_gdouble (parse->common.time_scale));
     if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
       gst_segment_set_duration (&parse->segment, GST_FORMAT_TIME, dur_u);
   }
@@ -2994,7 +2443,8 @@ gst_matroska_parse_parse_metadata_id_simple_tag (GstMatroskaParse * parse,
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "SimpleTag", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SimpleTag", id);
         break;
         /* fall-through */
 
@@ -3080,7 +2530,8 @@ gst_matroska_parse_parse_metadata_id_tag (GstMatroskaParse * parse,
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Tag", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "Tag", id);
         break;
     }
   }
@@ -3136,7 +2587,8 @@ gst_matroska_parse_parse_metadata (GstMatroskaParse * parse, GstEbmlRead * ebml)
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Tags", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "Tags", id);
         break;
         /* FIXME: Use to limit the tags to specific pads */
       case GST_MATROSKA_ID_TARGETS:
@@ -3219,7 +2671,8 @@ gst_matroska_parse_parse_attached_file (GstMatroskaParse * parse,
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "AttachedFile", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "AttachedFile", id);
         break;
       case GST_MATROSKA_ID_FILEUID:
         ret = gst_ebml_read_skip (ebml);
@@ -3332,7 +2785,8 @@ gst_matroska_parse_parse_attachments (GstMatroskaParse * parse,
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Attachments", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "Attachments", id);
         break;
     }
   }
@@ -3498,14 +2952,15 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
         size -= n;
 
         /* fetch stream from num */
-        stream_num = gst_matroska_parse_stream_from_num (parse, num);
+        stream_num = gst_matroska_read_common_stream_from_num (&parse->common,
+            num);
         if (G_UNLIKELY (size < 3)) {
           GST_WARNING_OBJECT (parse, "Invalid size %u", size);
           /* non-fatal, try next block(group) */
           ret = GST_FLOW_OK;
           goto done;
         } else if (G_UNLIKELY (stream_num < 0 ||
-                stream_num >= parse->num_streams)) {
+                stream_num >= parse->common.num_streams)) {
           /* let's not give up on a stray invalid track number */
           GST_WARNING_OBJECT (parse,
               "Invalid stream %d for track number %" G_GUINT64_FORMAT
@@ -3513,7 +2968,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
           goto done;
         }
 
-        stream = g_ptr_array_index (parse->src, stream_num);
+        stream = g_ptr_array_index (parse->common.src, stream_num);
 
         /* time (relative to cluster time) */
         time = ((gint16) GST_READ_UINT16_BE (data));
@@ -3640,7 +3095,8 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "BlockGroup", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "BlockGroup", id);
         break;
 
       case GST_MATROSKA_ID_BLOCKVIRTUAL:
@@ -3667,7 +3123,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
     gint64 lace_time = 0;
     gboolean delta_unit;
 
-    stream = g_ptr_array_index (parse->src, stream_num);
+    stream = g_ptr_array_index (parse->common.src, stream_num);
 
     if (cluster_time != GST_CLOCK_TIME_NONE) {
       /* FIXME: What to do with negative timestamps? Give timestamp 0 or -1?
@@ -3676,11 +3132,11 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
         lace_time = 0;
       } else {
         if (stream->timecodescale == 1.0)
-          lace_time = (cluster_time + time) * parse->time_scale;
+          lace_time = (cluster_time + time) * parse->common.time_scale;
         else
           lace_time =
               gst_util_guint64_to_gdouble ((cluster_time + time) *
-              parse->time_scale) * stream->timecodescale;
+              parse->common.time_scale) * stream->timecodescale;
       }
     } else {
       lace_time = GST_CLOCK_TIME_NONE;
@@ -3707,11 +3163,12 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
 
     if (block_duration) {
       if (stream->timecodescale == 1.0)
-        duration = gst_util_uint64_scale (block_duration, parse->time_scale, 1);
+        duration = gst_util_uint64_scale (block_duration,
+            parse->common.time_scale, 1);
       else
         duration =
             gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble
-            (gst_util_uint64_scale (block_duration, parse->time_scale,
+            (gst_util_uint64_scale (block_duration, parse->common.time_scale,
                     1)) * stream->timecodescale);
     } else if (stream->default_duration) {
       duration = stream->default_duration * laces;
@@ -4041,7 +3498,8 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse,
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SeekHead", id);
         break;
     }
   }
@@ -4077,17 +3535,18 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse,
       }
 
       /* check for validity */
-      if (seek_pos + parse->ebml_segment_start + 12 >= length) {
+      if (seek_pos + parse->common.ebml_segment_start + 12 >= length) {
         GST_WARNING_OBJECT (parse,
             "SeekHead reference lies outside file!" " (%"
             G_GUINT64_FORMAT "+%" G_GUINT64_FORMAT "+12 >= %"
-            G_GUINT64_FORMAT ")", seek_pos, parse->ebml_segment_start, length);
+            G_GUINT64_FORMAT ")", seek_pos, parse->common.ebml_segment_start,
+            length);
         break;
       }
 
       /* only pick up index location when streaming */
       if (seek_id == GST_MATROSKA_ID_CUES) {
-        parse->index_offset = seek_pos + parse->ebml_segment_start;
+        parse->index_offset = seek_pos + parse->common.ebml_segment_start;
         GST_DEBUG_OBJECT (parse, "Cues located at offset %" G_GUINT64_FORMAT,
             parse->index_offset);
       }
@@ -4133,7 +3592,8 @@ gst_matroska_parse_parse_contents (GstMatroskaParse * parse, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SeekHead", id);
         break;
     }
   }
@@ -4415,15 +3875,15 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
   if (G_LIKELY (length != G_MAXUINT64))
     read += needed;
 
-  switch (parse->state) {
-    case GST_MATROSKA_PARSE_STATE_START:
+  switch (parse->common.state) {
+    case GST_MATROSKA_READ_STATE_START:
       switch (id) {
         case GST_EBML_ID_HEADER:
           GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
           ret = gst_matroska_parse_parse_header (parse, &ebml);
           if (ret != GST_FLOW_OK)
             goto parse_failed;
-          parse->state = GST_MATROSKA_PARSE_STATE_SEGMENT;
+          parse->common.state = GST_MATROSKA_READ_STATE_SEGMENT;
           gst_matroska_parse_check_seekability (parse);
           gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
           break;
@@ -4432,7 +3892,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
           break;
       }
       break;
-    case GST_MATROSKA_PARSE_STATE_SEGMENT:
+    case GST_MATROSKA_READ_STATE_SEGMENT:
       switch (id) {
         case GST_MATROSKA_ID_SEGMENT:
           /* eat segment prefix */
@@ -4442,8 +3902,8 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
               parse->offset);
           /* seeks are from the beginning of the segment,
            * after the segment ID/length */
-          parse->ebml_segment_start = parse->offset;
-          parse->state = GST_MATROSKA_PARSE_STATE_HEADER;
+          parse->common.ebml_segment_start = parse->offset;
+          parse->common.state = GST_MATROSKA_READ_STATE_HEADER;
           gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
           break;
         default:
@@ -4455,14 +3915,14 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
           break;
       }
       break;
-    case GST_MATROSKA_PARSE_STATE_SCANNING:
+    case GST_MATROSKA_READ_STATE_SCANNING:
       if (id != GST_MATROSKA_ID_CLUSTER &&
           id != GST_MATROSKA_ID_CLUSTERTIMECODE)
         goto skip;
       /* fall-through */
-    case GST_MATROSKA_PARSE_STATE_HEADER:
-    case GST_MATROSKA_PARSE_STATE_DATA:
-    case GST_MATROSKA_PARSE_STATE_SEEK:
+    case GST_MATROSKA_READ_STATE_HEADER:
+    case GST_MATROSKA_READ_STATE_DATA:
+    case GST_MATROSKA_READ_STATE_SEEK:
       switch (id) {
         case GST_MATROSKA_ID_SEGMENTINFO:
           GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
@@ -4483,8 +3943,9 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
             GST_DEBUG_OBJECT (parse, "Cluster before Track");
             goto not_streamable;
           }
-          if (G_UNLIKELY (parse->state == GST_MATROSKA_PARSE_STATE_HEADER)) {
-            parse->state = GST_MATROSKA_PARSE_STATE_DATA;
+          if (G_UNLIKELY (parse->common.state
+                  == GST_MATROSKA_READ_STATE_HEADER)) {
+            parse->common.state = GST_MATROSKA_READ_STATE_DATA;
             parse->first_cluster_offset = parse->offset;
             GST_DEBUG_OBJECT (parse, "signaling no more pads");
           }
@@ -4514,16 +3975,17 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
             goto parse_failed;
           GST_DEBUG_OBJECT (parse, "ClusterTimeCode: %" G_GUINT64_FORMAT, num);
           parse->cluster_time = num;
-          if (parse->element_index) {
-            if (parse->element_index_writer_id == -1)
-              gst_index_get_writer_id (parse->element_index,
-                  GST_OBJECT (parse), &parse->element_index_writer_id);
+          if (parse->common.element_index) {
+            if (parse->common.element_index_writer_id == -1)
+              gst_index_get_writer_id (parse->common.element_index,
+                  GST_OBJECT (parse), &parse->common.element_index_writer_id);
             GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %"
                 G_GUINT64_FORMAT " for writer id %d",
                 GST_TIME_ARGS (parse->cluster_time), parse->cluster_offset,
-                parse->element_index_writer_id);
-            gst_index_add_association (parse->element_index,
-                parse->element_index_writer_id, GST_ASSOCIATION_FLAG_KEY_UNIT,
+                parse->common.element_index_writer_id);
+            gst_index_add_association (parse->common.element_index,
+                parse->common.element_index_writer_id,
+                GST_ASSOCIATION_FLAG_KEY_UNIT,
                 GST_FORMAT_TIME, parse->cluster_time,
                 GST_FORMAT_BYTES, parse->cluster_offset, NULL);
           }
@@ -4576,11 +4038,11 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
           break;
         case GST_MATROSKA_ID_CUES:
           GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
-          if (!parse->index_parsed) {
-            ret = gst_matroska_parse_parse_index (parse, &ebml);
+          if (!parse->common.index_parsed) {
+            ret = gst_matroska_read_common_parse_index (&parse->common, &ebml);
             /* only push based; delayed index building */
             if (ret == GST_FLOW_OK
-                && parse->state == GST_MATROSKA_PARSE_STATE_SEEK) {
+                && parse->common.state == GST_MATROSKA_READ_STATE_SEEK) {
               GstEvent *event;
 
               GST_OBJECT_LOCK (parse);
@@ -4594,7 +4056,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
                 goto seek_failed;
               /* resume data handling, main thread clear to seek again */
               GST_OBJECT_LOCK (parse);
-              parse->state = GST_MATROSKA_PARSE_STATE_DATA;
+              parse->common.state = GST_MATROSKA_READ_STATE_DATA;
               GST_OBJECT_UNLOCK (parse);
             }
           }
@@ -4679,7 +4141,7 @@ gst_matroska_parse_loop (GstPad * pad)
   guint needed;
 
   /* If we have to close a segment, send a new segment to do this now */
-  if (G_LIKELY (parse->state == GST_MATROSKA_PARSE_STATE_DATA)) {
+  if (G_LIKELY (parse->common.state == GST_MATROSKA_READ_STATE_DATA)) {
     if (G_UNLIKELY (parse->close_segment)) {
       gst_matroska_parse_send_event (parse, parse->close_segment);
       parse->close_segment = NULL;
@@ -4917,7 +4379,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
           "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
           &segment);
 
-      if (parse->state < GST_MATROSKA_PARSE_STATE_DATA) {
+      if (parse->common.state < GST_MATROSKA_READ_STATE_DATA) {
         GST_DEBUG_OBJECT (parse, "still starting");
         goto exit;
       }
@@ -4951,11 +4413,11 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
     }
     case GST_EVENT_EOS:
     {
-      if (parse->state != GST_MATROSKA_PARSE_STATE_DATA) {
+      if (parse->common.state != GST_MATROSKA_READ_STATE_DATA) {
         gst_event_unref (event);
         GST_ELEMENT_ERROR (parse, STREAM, DEMUX,
             (NULL), ("got eos and didn't receive a complete header object"));
-      } else if (parse->num_streams == 0) {
+      } else if (parse->common.num_streams == 0) {
         GST_ELEMENT_ERROR (parse, STREAM, DEMUX,
             (NULL), ("got eos but no streams (yet)"));
       } else {
@@ -4988,11 +4450,12 @@ gst_matroska_parse_set_index (GstElement * element, GstIndex * index)
   GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
 
   GST_OBJECT_LOCK (parse);
-  if (parse->element_index)
-    gst_object_unref (parse->element_index);
-  parse->element_index = index ? gst_object_ref (index) : NULL;
+  if (parse->common.element_index)
+    gst_object_unref (parse->common.element_index);
+  parse->common.element_index = index ? gst_object_ref (index) : NULL;
   GST_OBJECT_UNLOCK (parse);
-  GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT, parse->element_index);
+  GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT,
+      parse->common.element_index);
 }
 
 static GstIndex *
@@ -5002,8 +4465,8 @@ gst_matroska_parse_get_index (GstElement * element)
   GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
 
   GST_OBJECT_LOCK (parse);
-  if (parse->element_index)
-    result = gst_object_ref (parse->element_index);
+  if (parse->common.element_index)
+    result = gst_object_ref (parse->common.element_index);
   GST_OBJECT_UNLOCK (parse);
 
   GST_DEBUG_OBJECT (parse, "Returning index %" GST_PTR_FORMAT, result);
index 595ead2..98b399d 100644 (file)
@@ -1,5 +1,6 @@
 /* GStreamer Matroska muxer/demuxer
  * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
  *
  * matroska-parse.h: matroska file/stream parseer definition
  *
@@ -27,6 +28,7 @@
 
 #include "ebml-read.h"
 #include "matroska-ids.h"
+#include "matroska-read-common.h"
 
 G_BEGIN_DECLS
 
@@ -41,29 +43,17 @@ G_BEGIN_DECLS
 #define GST_IS_MATROSKA_PARSE_CLASS(klass) \
   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_PARSE))
 
-typedef enum {
-  GST_MATROSKA_PARSE_STATE_START,
-  GST_MATROSKA_PARSE_STATE_SEGMENT,
-  GST_MATROSKA_PARSE_STATE_HEADER,
-  GST_MATROSKA_PARSE_STATE_DATA,
-  GST_MATROSKA_PARSE_STATE_SEEK,
-  GST_MATROSKA_PARSE_STATE_SCANNING
-} GstMatroskaParseState;
-
 typedef struct _GstMatroskaParse {
   GstElement              parent;
 
   /* < private > */
 
-  GstIndex                *element_index;
-  gint                     element_index_writer_id;
+  GstMatroskaReadCommon    common;
 
   /* pads */
   GstPad                  *sinkpad;
   GstPad                  *srcpad;
-  GPtrArray               *src;
   GstClock                *clock;
-  guint                    num_streams;
   guint                    num_v_streams;
   guint                    num_a_streams;
   guint                    num_t_streams;
@@ -79,28 +69,17 @@ typedef struct _GstMatroskaParse {
 
   /* state */
   //gboolean                 streaming;
-  GstMatroskaParseState    state;
   guint                    level_up;
   guint64                  seek_block;
   gboolean                 seek_first;
 
   /* did we parse cues/tracks/segmentinfo already? */
-  gboolean                 index_parsed;
   gboolean                 tracks_parsed;
   gboolean                 segmentinfo_parsed;
   gboolean                 attachments_parsed;
   GList                   *tags_parsed;
   GList                   *seek_parsed;
 
-  /* start-of-segment */
-  guint64                  ebml_segment_start;
-
-  /* a cue (index) table */
-  GArray                  *index;
-
-  /* timescale in the file */
-  guint64                  time_scale;
-
   /* keeping track of playback position */
   GstSegment               segment;
   gboolean                 segment_running;
diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c
new file mode 100644 (file)
index 0000000..5729688
--- /dev/null
@@ -0,0 +1,609 @@
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Tim-Philipp Müller <tim centricular net>
+ * (c) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
+ *
+ * matroska-read-common.c: shared by matroska file/stream demuxer and parser
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+#ifdef HAVE_BZ2
+#include <bzlib.h>
+#endif
+
+#include "lzo.h"
+
+#include "ebml-read.h"
+#include "matroska-read-common.h"
+
+GST_DEBUG_CATEGORY_STATIC (matroskareadcommon_debug);
+#define GST_CAT_DEFAULT matroskareadcommon_debug
+
+#define DEBUG_ELEMENT_START(common, ebml, element) \
+    GST_DEBUG_OBJECT (common, "Parsing " element " element at offset %" \
+        G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml))
+
+#define DEBUG_ELEMENT_STOP(common, ebml, element, ret) \
+    GST_DEBUG_OBJECT (common, "Parsing " element " element " \
+        " finished with '%s'", gst_flow_get_name (ret))
+
+GstFlowReturn
+gst_matroska_decode_content_encodings (GArray * encodings)
+{
+  gint i;
+
+  if (encodings == NULL)
+    return GST_FLOW_OK;
+
+  for (i = 0; i < encodings->len; i++) {
+    GstMatroskaTrackEncoding *enc =
+        &g_array_index (encodings, GstMatroskaTrackEncoding, i);
+    guint8 *data = NULL;
+    guint size;
+
+    if ((enc->scope & GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING)
+        == 0)
+      continue;
+
+    /* Encryption not supported yet */
+    if (enc->type != 0)
+      return GST_FLOW_ERROR;
+
+    if (i + 1 >= encodings->len)
+      return GST_FLOW_ERROR;
+
+    if (enc->comp_settings_length == 0)
+      continue;
+
+    data = enc->comp_settings;
+    size = enc->comp_settings_length;
+
+    if (!gst_matroska_decompress_data (enc, &data, &size, enc->comp_algo))
+      return GST_FLOW_ERROR;
+
+    g_free (enc->comp_settings);
+
+    enc->comp_settings = data;
+    enc->comp_settings_length = size;
+  }
+
+  return GST_FLOW_OK;
+}
+
+gboolean
+gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
+    guint8 ** data_out, guint * size_out,
+    GstMatroskaTrackCompressionAlgorithm algo)
+{
+  guint8 *new_data = NULL;
+  guint new_size = 0;
+  guint8 *data = *data_out;
+  guint size = *size_out;
+  gboolean ret = TRUE;
+
+  if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB) {
+#ifdef HAVE_ZLIB
+    /* zlib encoded data */
+    z_stream zstream;
+    guint orig_size;
+    int result;
+
+    orig_size = size;
+    zstream.zalloc = (alloc_func) 0;
+    zstream.zfree = (free_func) 0;
+    zstream.opaque = (voidpf) 0;
+    if (inflateInit (&zstream) != Z_OK) {
+      GST_WARNING ("zlib initialization failed.");
+      ret = FALSE;
+      goto out;
+    }
+    zstream.next_in = (Bytef *) data;
+    zstream.avail_in = orig_size;
+    new_size = orig_size;
+    new_data = g_malloc (new_size);
+    zstream.avail_out = new_size;
+    zstream.next_out = (Bytef *) new_data;
+
+    do {
+      result = inflate (&zstream, Z_NO_FLUSH);
+      if (result != Z_OK && result != Z_STREAM_END) {
+        GST_WARNING ("zlib decompression failed.");
+        g_free (new_data);
+        inflateEnd (&zstream);
+        break;
+      }
+      new_size += 4000;
+      new_data = g_realloc (new_data, new_size);
+      zstream.next_out = (Bytef *) (new_data + zstream.total_out);
+      zstream.avail_out += 4000;
+    } while (zstream.avail_in != 0 && result != Z_STREAM_END);
+
+    if (result != Z_STREAM_END) {
+      ret = FALSE;
+      goto out;
+    } else {
+      new_size = zstream.total_out;
+      inflateEnd (&zstream);
+    }
+#else
+    GST_WARNING ("zlib encoded tracks not supported.");
+    ret = FALSE;
+    goto out;
+#endif
+  } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB) {
+#ifdef HAVE_BZ2
+    /* bzip2 encoded data */
+    bz_stream bzstream;
+    guint orig_size;
+    int result;
+
+    bzstream.bzalloc = NULL;
+    bzstream.bzfree = NULL;
+    bzstream.opaque = NULL;
+    orig_size = size;
+
+    if (BZ2_bzDecompressInit (&bzstream, 0, 0) != BZ_OK) {
+      GST_WARNING ("bzip2 initialization failed.");
+      ret = FALSE;
+      goto out;
+    }
+
+    bzstream.next_in = (char *) data;
+    bzstream.avail_in = orig_size;
+    new_size = orig_size;
+    new_data = g_malloc (new_size);
+    bzstream.avail_out = new_size;
+    bzstream.next_out = (char *) new_data;
+
+    do {
+      result = BZ2_bzDecompress (&bzstream);
+      if (result != BZ_OK && result != BZ_STREAM_END) {
+        GST_WARNING ("bzip2 decompression failed.");
+        g_free (new_data);
+        BZ2_bzDecompressEnd (&bzstream);
+        break;
+      }
+      new_size += 4000;
+      new_data = g_realloc (new_data, new_size);
+      bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32);
+      bzstream.avail_out += 4000;
+    } while (bzstream.avail_in != 0 && result != BZ_STREAM_END);
+
+    if (result != BZ_STREAM_END) {
+      ret = FALSE;
+      goto out;
+    } else {
+      new_size = bzstream.total_out_lo32;
+      BZ2_bzDecompressEnd (&bzstream);
+    }
+#else
+    GST_WARNING ("bzip2 encoded tracks not supported.");
+    ret = FALSE;
+    goto out;
+#endif
+  } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X) {
+    /* lzo encoded data */
+    int result;
+    int orig_size, out_size;
+
+    orig_size = size;
+    out_size = size;
+    new_size = size;
+    new_data = g_malloc (new_size);
+
+    do {
+      orig_size = size;
+      out_size = new_size;
+
+      result = lzo1x_decode (new_data, &out_size, data, &orig_size);
+
+      if (orig_size > 0) {
+        new_size += 4000;
+        new_data = g_realloc (new_data, new_size);
+      }
+    } while (orig_size > 0 && result == LZO_OUTPUT_FULL);
+
+    new_size -= out_size;
+
+    if (result != LZO_OUTPUT_FULL) {
+      GST_WARNING ("lzo decompression failed");
+      g_free (new_data);
+
+      ret = FALSE;
+      goto out;
+    }
+
+  } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP) {
+    /* header stripped encoded data */
+    if (enc->comp_settings_length > 0) {
+      new_data = g_malloc (size + enc->comp_settings_length);
+      new_size = size + enc->comp_settings_length;
+
+      memcpy (new_data, enc->comp_settings, enc->comp_settings_length);
+      memcpy (new_data + enc->comp_settings_length, data, size);
+    }
+  } else {
+    GST_ERROR ("invalid compression algorithm %d", algo);
+    ret = FALSE;
+  }
+
+out:
+
+  if (!ret) {
+    *data_out = NULL;
+    *size_out = 0;
+  } else {
+    *data_out = new_data;
+    *size_out = new_size;
+  }
+
+  return ret;
+}
+
+static gint
+gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2)
+{
+  if (i1->time < i2->time)
+    return -1;
+  else if (i1->time > i2->time)
+    return 1;
+  else if (i1->block < i2->block)
+    return -1;
+  else if (i1->block > i2->block)
+    return 1;
+  else
+    return 0;
+}
+
+/* skip unknown or alike element */
+GstFlowReturn
+gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, const gchar * parent_name, guint id)
+{
+  if (id == GST_EBML_ID_VOID) {
+    GST_DEBUG_OBJECT (common, "Skipping EBML Void element");
+  } else if (id == GST_EBML_ID_CRC32) {
+    GST_DEBUG_OBJECT (common, "Skipping EBML CRC32 element");
+  } else {
+    GST_WARNING_OBJECT (common,
+        "Unknown %s subelement 0x%x - ignoring", parent_name, id);
+  }
+
+  return gst_ebml_read_skip (ebml);
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, guint * nentries)
+{
+  guint32 id;
+  GstFlowReturn ret;
+  GstMatroskaIndex idx;
+
+  idx.pos = (guint64) - 1;
+  idx.track = 0;
+  idx.time = GST_CLOCK_TIME_NONE;
+  idx.block = 1;
+
+  DEBUG_ELEMENT_START (common, ebml, "CueTrackPositions");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
+    return ret;
+  }
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      break;
+
+    switch (id) {
+        /* track number */
+      case GST_MATROSKA_ID_CUETRACK:
+      {
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num == 0) {
+          idx.track = 0;
+          GST_WARNING_OBJECT (common, "Invalid CueTrack 0");
+          break;
+        }
+
+        GST_DEBUG_OBJECT (common, "CueTrack: %" G_GUINT64_FORMAT, num);
+        idx.track = num;
+        break;
+      }
+
+        /* position in file */
+      case GST_MATROSKA_ID_CUECLUSTERPOSITION:
+      {
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num > G_MAXINT64) {
+          GST_WARNING_OBJECT (common, "CueClusterPosition %" G_GUINT64_FORMAT
+              " too large", num);
+          break;
+        }
+
+        idx.pos = num;
+        break;
+      }
+
+        /* number of block in the cluster */
+      case GST_MATROSKA_ID_CUEBLOCKNUMBER:
+      {
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num == 0) {
+          GST_WARNING_OBJECT (common, "Invalid CueBlockNumber 0");
+          break;
+        }
+
+        GST_DEBUG_OBJECT (common, "CueBlockNumber: %" G_GUINT64_FORMAT, num);
+        idx.block = num;
+
+        /* mild sanity check, disregard strange cases ... */
+        if (idx.block > G_MAXUINT16) {
+          GST_DEBUG_OBJECT (common, "... looks suspicious, ignoring");
+          idx.block = 1;
+        }
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml,
+            "CueTrackPositions", id);
+        break;
+
+      case GST_MATROSKA_ID_CUECODECSTATE:
+      case GST_MATROSKA_ID_CUEREFERENCE:
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
+
+  if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
+      && idx.pos != (guint64) - 1 && idx.track > 0) {
+    g_array_append_val (common->index, idx);
+    (*nentries)++;
+  } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) {
+    GST_DEBUG_OBJECT (common, "CueTrackPositions without valid content");
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_index_pointentry (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml)
+{
+  guint32 id;
+  GstFlowReturn ret;
+  GstClockTime time = GST_CLOCK_TIME_NONE;
+  guint nentries = 0;
+
+  DEBUG_ELEMENT_START (common, ebml, "CuePoint");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret);
+    return ret;
+  }
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      break;
+
+    switch (id) {
+        /* one single index entry ('point') */
+      case GST_MATROSKA_ID_CUETIME:
+      {
+        if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (common, "CueTime: %" G_GUINT64_FORMAT, time);
+        time = time * common->time_scale;
+        break;
+      }
+
+        /* position in the file + track to which it belongs */
+      case GST_MATROSKA_ID_CUETRACKPOSITIONS:
+      {
+        if ((ret =
+                gst_matroska_read_common_parse_index_cuetrack (common, ebml,
+                    &nentries)) != GST_FLOW_OK)
+          break;
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml, "CuePoint",
+            id);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret);
+
+  if (nentries > 0) {
+    if (time == GST_CLOCK_TIME_NONE) {
+      GST_WARNING_OBJECT (common, "CuePoint without valid time");
+      g_array_remove_range (common->index, common->index->len - nentries,
+          nentries);
+    } else {
+      gint i;
+
+      for (i = common->index->len - nentries; i < common->index->len; i++) {
+        GstMatroskaIndex *idx =
+            &g_array_index (common->index, GstMatroskaIndex, i);
+
+        idx->time = time;
+        GST_DEBUG_OBJECT (common, "Index entry: pos=%" G_GUINT64_FORMAT
+            ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
+            GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
+      }
+    }
+  } else {
+    GST_DEBUG_OBJECT (common, "Empty CuePoint");
+  }
+
+  return ret;
+}
+
+gint
+gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common,
+    guint track_num)
+{
+  guint n;
+
+  g_assert (common->src->len == common->num_streams);
+  for (n = 0; n < common->src->len; n++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (common->src, n);
+
+    if (context->num == track_num) {
+      return n;
+    }
+  }
+
+  if (n == common->num_streams)
+    GST_WARNING_OBJECT (common,
+        "Failed to find corresponding pad for tracknum %d", track_num);
+
+  return -1;
+}
+
+GstFlowReturn
+gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml)
+{
+  guint32 id;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint i;
+
+  if (common->index)
+    g_array_free (common->index, TRUE);
+  common->index =
+      g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
+
+  DEBUG_ELEMENT_START (common, ebml, "Cues");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret);
+    return ret;
+  }
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      break;
+
+    switch (id) {
+        /* one single index entry ('point') */
+      case GST_MATROSKA_ID_POINTENTRY:
+        ret = gst_matroska_read_common_parse_index_pointentry (common, ebml);
+        break;
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml, "Cues", id);
+        break;
+    }
+  }
+  DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret);
+
+  /* Sort index by time, smallest time first, for easier searching */
+  g_array_sort (common->index, (GCompareFunc) gst_matroska_index_compare);
+
+  /* Now sort the track specific index entries into their own arrays */
+  for (i = 0; i < common->index->len; i++) {
+    GstMatroskaIndex *idx = &g_array_index (common->index, GstMatroskaIndex,
+        i);
+    gint track_num;
+    GstMatroskaTrackContext *ctx;
+
+    if (common->element_index) {
+      gint writer_id;
+
+      if (idx->track != 0 &&
+          (track_num =
+              gst_matroska_read_common_stream_from_num (common,
+                  idx->track)) != -1) {
+        ctx = g_ptr_array_index (common->src, track_num);
+
+        if (ctx->index_writer_id == -1)
+          gst_index_get_writer_id (common->element_index,
+              GST_OBJECT (ctx->pad), &ctx->index_writer_id);
+        writer_id = ctx->index_writer_id;
+      } else {
+        if (common->element_index_writer_id == -1)
+          gst_index_get_writer_id (common->element_index, GST_OBJECT (common),
+              &common->element_index_writer_id);
+        writer_id = common->element_index_writer_id;
+      }
+
+      GST_LOG_OBJECT (common, "adding association %" GST_TIME_FORMAT "-> %"
+          G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time),
+          idx->pos, writer_id);
+      gst_index_add_association (common->element_index, writer_id,
+          GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time,
+          GST_FORMAT_BYTES, idx->pos + common->ebml_segment_start, NULL);
+    }
+
+    if (idx->track == 0)
+      continue;
+
+    track_num = gst_matroska_read_common_stream_from_num (common, idx->track);
+    if (track_num == -1)
+      continue;
+
+    ctx = g_ptr_array_index (common->src, track_num);
+
+    if (ctx->index_table == NULL)
+      ctx->index_table =
+          g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
+
+    g_array_append_vals (ctx->index_table, idx, 1);
+  }
+
+  common->index_parsed = TRUE;
+
+  /* sanity check; empty index normalizes to no index */
+  if (common->index->len == 0) {
+    g_array_free (common->index, TRUE);
+    common->index = NULL;
+  }
+
+  return ret;
+}
diff --git a/gst/matroska/matroska-read-common.h b/gst/matroska/matroska-read-common.h
new file mode 100644 (file)
index 0000000..cbe7103
--- /dev/null
@@ -0,0 +1,79 @@
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
+ *
+ * matroska-read-common.h: shared by matroska file/stream demuxer and parser
+ *
+ * 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_MATROSKA_READ_COMMON_H__
+#define __GST_MATROSKA_READ_COMMON_H__
+
+#include <glib.h>
+#include <gst/gst.h>
+
+#include "matroska-ids.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GST_MATROSKA_READ_STATE_START,
+  GST_MATROSKA_READ_STATE_SEGMENT,
+  GST_MATROSKA_READ_STATE_HEADER,
+  GST_MATROSKA_READ_STATE_DATA,
+  GST_MATROSKA_READ_STATE_SEEK,
+  GST_MATROSKA_READ_STATE_SCANNING
+} GstMatroskaReadState;
+
+typedef struct _GstMatroskaReadCommon {
+  GstIndex                *element_index;
+  gint                     element_index_writer_id;
+
+  /* pads */
+  GPtrArray               *src;
+  guint                    num_streams;
+
+  /* state */
+  GstMatroskaReadState     state;
+
+  /* did we parse cues/tracks/segmentinfo already? */
+  gboolean                 index_parsed;
+
+  /* start-of-segment */
+  guint64                  ebml_segment_start;
+
+  /* a cue (index) table */
+  GArray                  *index;
+
+  /* timescale in the file */
+  guint64                  time_scale;
+} GstMatroskaReadCommon;
+
+GstFlowReturn gst_matroska_decode_content_encodings (GArray * encodings);
+gboolean gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
+    guint8 ** data_out, guint * size_out,
+    GstMatroskaTrackCompressionAlgorithm algo);
+GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml);
+GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml, const gchar * parent_name, guint id);
+gint gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common,
+    guint track_num);
+
+G_END_DECLS
+
+#endif /* __GST_MATROSKA_READ_COMMON_H__ */
index 099be64..17da501 100644 (file)
@@ -190,8 +190,9 @@ gst_rtp_ac3_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 
   gst_rtp_buffer_unmap (&rtp);
 
-  GST_DEBUG_OBJECT (rtpac3depay, "pushing buffer of size %d",
-      gst_buffer_get_size (outbuf));
+  if (outbuf)
+    GST_DEBUG_OBJECT (rtpac3depay, "pushing buffer of size %d",
+        gst_buffer_get_size (outbuf));
 
   return outbuf;
 
index a01aa47..7b8d67f 100644 (file)
@@ -166,7 +166,7 @@ gst_rtp_bv_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
   outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
   gst_rtp_buffer_unmap (&rtp);
 
-  if (marker) {
+  if (marker && outbuf) {
     /* mark start of talkspurt with DISCONT */
     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
   }
index 8f0f2c5..e792e60 100644 (file)
@@ -235,7 +235,7 @@ gst_rtp_g722_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
   marker = gst_rtp_buffer_get_marker (&rtp);
   gst_rtp_buffer_unmap (&rtp);
 
-  if (marker) {
+  if (marker && outbuf) {
     /* mark talk spurt with DISCONT */
     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
   }
index cf88bd6..2f34a0d 100644 (file)
@@ -222,6 +222,8 @@ gst_rtp_g726_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
   if (depay->aal2 || depay->force_aal2) {
     /* AAL2, we can just copy the bytes */
     outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+    if (!outbuf)
+      goto bad_len;
   } else {
     guint8 *in, *out, tmp, *odata;
     guint len;
@@ -231,6 +233,8 @@ gst_rtp_g726_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
     len = gst_rtp_buffer_get_payload_len (&rtp);
 
     outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+    if (!outbuf)
+      goto bad_len;
     outbuf = gst_buffer_make_writable (outbuf);
 
     odata = gst_buffer_map (outbuf, &osize, NULL, GST_MAP_WRITE);
@@ -331,6 +335,9 @@ gst_rtp_g726_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
   }
 
   return outbuf;
+
+bad_len:
+  return NULL;
 }
 
 static void
index 30f6a7f..298708a 100644 (file)
@@ -136,7 +136,7 @@ gst_rtp_gsm_depay_process (GstBaseRTPDepayload * _depayload, GstBuffer * buf)
 
   gst_rtp_buffer_unmap (&rtp);
 
-  if (marker) {
+  if (marker && outbuf) {
     /* mark start of talkspurt with DISCONT */
     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
   }
index 6c22596..f8e8ab5 100644 (file)
@@ -190,7 +190,7 @@ gst_rtp_ilbc_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 
   gst_rtp_buffer_unmap (&rtp);
 
-  if (marker) {
+  if (marker && outbuf) {
     /* mark start of talkspurt with DISCONT */
     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
   }
index fc4096d..f223847 100644 (file)
@@ -716,7 +716,7 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload,
       guint qt;
 
       qt = info[i].qt;
-      if (qt > 15)
+      if (qt >= G_N_ELEMENTS (tables))
         goto invalid_quant;
 
       qsize = tables[qt].size;
index 4887c4c..b7063d6 100644 (file)
@@ -131,8 +131,9 @@ gst_rtp_mp1s_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 
   outbuf = gst_rtp_buffer_get_payload_buffer (buf);
 
-  GST_DEBUG ("gst_rtp_mp1s_depay_chain: pushing buffer of size %d",
-      GST_BUFFER_SIZE (outbuf));
+  if (outbuf)
+    GST_DEBUG ("gst_rtp_mp1s_depay_chain: pushing buffer of size %d",
+        GST_BUFFER_SIZE (outbuf));
 
   return outbuf;
 }
index fe6c5de..4f5e720 100644 (file)
@@ -169,8 +169,9 @@ gst_rtp_mp2t_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
       gst_rtp_buffer_get_payload_subbuffer (buf, rtpmp2tdepay->skip_first_bytes,
       -1);
 
-  GST_DEBUG ("gst_rtp_mp2t_depay_chain: pushing buffer of size %d",
-      GST_BUFFER_SIZE (outbuf));
+  if (outbuf)
+    GST_DEBUG ("gst_rtp_mp2t_depay_chain: pushing buffer of size %d",
+        GST_BUFFER_SIZE (outbuf));
 
   return outbuf;
 
index 18ebfd2..664864a 100644 (file)
@@ -51,7 +51,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
         /* All optional parameters
          *
          * "profile-level-id=[1,MAX]"
-         * "config=" 
+         * "config="
          */
     )
     );
@@ -229,7 +229,7 @@ gst_rtp_mp4a_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
 
       if (!gst_bit_reader_get_bits_uint8 (&br, &sr_idx, 4))
         goto bad_config;
-      if (sr_idx > 12 && sr_idx != 15) {
+      if (sr_idx >= G_N_ELEMENTS (aac_sample_rates) && sr_idx != 15) {
         GST_WARNING_OBJECT (depayload, "invalid sample rate index %d", sr_idx);
         goto bad_config;
       }
index d6e856b..c94eb63 100644 (file)
@@ -172,10 +172,11 @@ gst_rtp_mpv_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 
     outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, payload_header, -1);
 
-    GST_DEBUG_OBJECT (rtpmpvdepay,
-        "gst_rtp_mpv_depay_chain: pushing buffer of size %d",
-        gst_buffer_get_size (outbuf));
-
+    if (outbuf) {
+      GST_DEBUG_OBJECT (rtpmpvdepay,
+          "gst_rtp_mpv_depay_chain: pushing buffer of size %d",
+          gst_buffer_get_size (outbuf));
+    }
     return outbuf;
   }
 
index 27d463f..4d4a80e 100644 (file)
@@ -46,18 +46,18 @@ static GstStaticPadTemplate gst_rtp_pcma_depay_sink_template =
     GST_STATIC_CAPS ("application/x-rtp, "
         "media = (string) \"audio\", "
         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
-        "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMA\";"
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"PCMA\";"
         "application/x-rtp, "
         "media = (string) \"audio\", "
         "payload = (int) " GST_RTP_PAYLOAD_PCMA_STRING ", "
-        "clock-rate = (int) 8000")
+        "clock-rate = (int) [1, MAX ]")
     );
 
 static GstStaticPadTemplate gst_rtp_pcma_depay_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-alaw, channels = (int) 1, rate = (int) 8000")
+    GST_STATIC_CAPS ("audio/x-alaw, channels = (int) 1, rate = (int) [1, MAX ]")
     );
 
 static GstBuffer *gst_rtp_pcma_depay_process (GstBaseRTPDepayload * depayload,
@@ -144,12 +144,14 @@ gst_rtp_pcma_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
   outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
   gst_rtp_buffer_unmap (&rtp);
 
-  GST_BUFFER_DURATION (outbuf) =
-      gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);
+  if (outbuf) {
+    GST_BUFFER_DURATION (outbuf) =
+        gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);
 
-  if (marker) {
-    /* mark start of talkspurt with DISCONT */
-    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    if (marker) {
+      /* mark start of talkspurt with DISCONT */
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    }
   }
 
 
index 0a208cd..36dfd46 100644 (file)
@@ -46,18 +46,19 @@ static GstStaticPadTemplate gst_rtp_pcmu_depay_sink_template =
     GST_STATIC_CAPS ("application/x-rtp, "
         "media = (string) \"audio\", "
         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
-        "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMU\";"
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"PCMU\";"
         "application/x-rtp, "
         "media = (string) \"audio\", "
         "payload = (int) " GST_RTP_PAYLOAD_PCMU_STRING ", "
-        "clock-rate = (int) 8000")
+        "clock-rate = (int) [1, MAX ]")
     );
 
 static GstStaticPadTemplate gst_rtp_pcmu_depay_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-mulaw, channels = (int) 1, rate = (int) 8000")
+    GST_STATIC_CAPS ("audio/x-mulaw, "
+        "channels = (int) 1, rate = (int) [1, MAX ]")
     );
 
 static GstBuffer *gst_rtp_pcmu_depay_process (GstBaseRTPDepayload * depayload,
@@ -144,12 +145,14 @@ gst_rtp_pcmu_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
   outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
   gst_rtp_buffer_unmap (&rtp);
 
-  GST_BUFFER_DURATION (outbuf) =
-      gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);
+  if (outbuf) {
+    GST_BUFFER_DURATION (outbuf) =
+        gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);
 
-  if (marker) {
-    /* mark start of talkspurt with DISCONT */
-    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    if (marker) {
+      /* mark start of talkspurt with DISCONT */
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    }
   }
 
   return outbuf;
index 7949ae7..ce947d4 100644 (file)
@@ -164,7 +164,7 @@ static const gint frame_size[16] = {
 static gint
 get_frame_len (GstRtpQCELPDepay * depay, guint8 frame_type)
 {
-  if (frame_type > 16)
+  if (frame_type >= G_N_ELEMENTS (frame_size))
     return 0;
 
   return frame_size[frame_type];
index 10dea1a..87e8a77 100644 (file)
@@ -212,7 +212,8 @@ gst_rtp_speex_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
   /* nothing special to be done */
   outbuf = gst_rtp_buffer_get_payload_buffer (buf);
 
-  GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND;
+  if (outbuf)
+    GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND;
 
   return outbuf;
 }
index 3a46360..d355813 100644 (file)
@@ -5502,8 +5502,10 @@ restart:
   src->need_redirect = FALSE;
 
   /* can't continue without a valid url */
-  if (G_UNLIKELY (src->conninfo.url == NULL))
+  if (G_UNLIKELY (src->conninfo.url == NULL)) {
+    res = GST_RTSP_EINVAL;
     goto no_url;
+  }
   src->tried_url_auth = FALSE;
 
   if ((res = gst_rtsp_conninfo_connect (src, &src->conninfo, async)) < 0)
index 7695956..3a55034 100644 (file)
@@ -56,7 +56,7 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
 #define DEFAULT_PROP_DEVICE_NAME       NULL
 #define DEFAULT_PROP_DEVICE_FD          -1
 #define DEFAULT_PROP_FLAGS              0
-#define DEFAULT_PROP_NORM               NULL
+#define DEFAULT_PROP_TV_NORM            0
 #define DEFAULT_PROP_CHANNEL            NULL
 #define DEFAULT_PROP_FREQUENCY          0
 
@@ -316,6 +316,58 @@ gst_v4l2_device_get_type (void)
   return v4l2_device_type;
 }
 
+#define GST_TYPE_V4L2_TV_NORM (gst_v4l2_tv_norm_get_type ())
+static GType
+gst_v4l2_tv_norm_get_type (void)
+{
+  static GType v4l2_tv_norm = 0;
+
+  if (!v4l2_tv_norm) {
+    static const GEnumValue tv_norms[] = {
+      {0, "none", "none"},
+
+      {V4L2_STD_NTSC, "NTSC", "NTSC"},
+      {V4L2_STD_NTSC_M, "NTSC-M", "NTSC-M"},
+      {V4L2_STD_NTSC_M_JP, "NTSC-M-JP", "NTSC-M-JP"},
+      {V4L2_STD_NTSC_M_KR, "NTSC-M-KR", "NTSC-M-KR"},
+      {V4L2_STD_NTSC_443, "NTSC-443", "NTSC-443"},
+
+      {V4L2_STD_PAL, "PAL", "PAL"},
+      {V4L2_STD_PAL_BG, "PAL-BG", "PAL-BG"},
+      {V4L2_STD_PAL_B, "PAL-B", "PAL-B"},
+      {V4L2_STD_PAL_B1, "PAL-B1", "PAL-B1"},
+      {V4L2_STD_PAL_G, "PAL-G", "PAL-G"},
+      {V4L2_STD_PAL_H, "PAL-H", "PAL-H"},
+      {V4L2_STD_PAL_I, "PAL-I", "PAL-I"},
+      {V4L2_STD_PAL_DK, "PAL-DK", "PAL-DK"},
+      {V4L2_STD_PAL_D, "PAL-D", "PAL-D"},
+      {V4L2_STD_PAL_D1, "PAL-D1", "PAL-D1"},
+      {V4L2_STD_PAL_K, "PAL-K", "PAL-K"},
+      {V4L2_STD_PAL_M, "PAL-M", "PAL-M"},
+      {V4L2_STD_PAL_N, "PAL-N", "PAL-N"},
+      {V4L2_STD_PAL_Nc, "PAL-Nc", "PAL-Nc"},
+      {V4L2_STD_PAL_60, "PAL-60", "PAL-60"},
+
+      {V4L2_STD_SECAM, "SECAM", "SECAM"},
+      {V4L2_STD_SECAM_B, "SECAM-B", "SECAM-B"},
+      {V4L2_STD_SECAM_G, "SECAM-G", "SECAM-G"},
+      {V4L2_STD_SECAM_H, "SECAM-H", "SECAM-H"},
+      {V4L2_STD_SECAM_DK, "SECAM-DK", "SECAM-DK"},
+      {V4L2_STD_SECAM_D, "SECAM-D", "SECAM-D"},
+      {V4L2_STD_SECAM_K, "SECAM-K", "SECAM-K"},
+      {V4L2_STD_SECAM_K1, "SECAM-K1", "SECAM-K1"},
+      {V4L2_STD_SECAM_L, "SECAM-L", "SECAM-L"},
+      {V4L2_STD_SECAM_LC, "SECAM-Lc", "SECAM-Lc"},
+
+      {0, NULL, NULL}
+    };
+
+    v4l2_tv_norm = g_enum_register_static ("V4L2_TV_norms", tv_norms);
+  }
+
+  return v4l2_tv_norm;
+}
+
 void
 gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
     const char *default_device)
@@ -384,6 +436,19 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
           "Hue or color balance", G_MININT,
           G_MAXINT, 0,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  /**
+   * GstV4l2Src:norm
+   *
+   * TV norm
+   *
+   * Since: 0.10.30
+   */
+  g_object_class_install_property (gobject_class, PROP_TV_NORM,
+      g_param_spec_enum ("norm", "TV norm",
+          "video standard",
+          GST_TYPE_V4L2_TV_NORM, DEFAULT_PROP_TV_NORM,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
 GstV4l2Object *
@@ -440,9 +505,6 @@ gst_v4l2_object_destroy (GstV4l2Object * v4l2object)
   if (v4l2object->channel)
     g_free (v4l2object->channel);
 
-  if (v4l2object->norm)
-    g_free (v4l2object->norm);
-
   if (v4l2object->formats) {
     gst_v4l2_object_clear_format_list (v4l2object);
   }
@@ -510,23 +572,10 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
       return TRUE;
     }
       break;
-#if 0
-    case PROP_NORM:
-      if (GST_V4L2_IS_OPEN (v4l2object)) {
-        GstTuner *tuner = GST_TUNER (v4l2object->element);
-        GstTunerNorm *norm = gst_tuner_find_norm_by_name (tuner,
-            (gchar *) g_value_get_string (value));
-
-        if (norm) {
-          /* like gst_tuner_set_norm (tuner, norm)
-             without g_object_notify */
-          gst_v4l2_tuner_set_norm (v4l2object, norm);
-        }
-      } else {
-        g_free (v4l2object->norm);
-        v4l2object->norm = g_value_dup_string (value);
-      }
+    case PROP_TV_NORM:
+      v4l2object->tv_norm = g_value_get_enum (value);
       break;
+#if 0
     case PROP_CHANNEL:
       if (GST_V4L2_IS_OPEN (v4l2object)) {
         GstTuner *tuner = GST_TUNER (v4l2object->element);
@@ -631,6 +680,9 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
       return TRUE;
     }
       break;
+    case PROP_TV_NORM:
+      g_value_set_enum (value, v4l2object->tv_norm);
+      break;
     default:
       return FALSE;
       break;
@@ -650,16 +702,18 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
 
   tuner = GST_TUNER (v4l2object->element);
 
-  if (v4l2object->norm)
-    norm = gst_tuner_find_norm_by_name (tuner, v4l2object->norm);
+  if (v4l2object->tv_norm)
+    norm = gst_v4l2_tuner_get_norm_by_std_id (v4l2object, v4l2object->tv_norm);
+  GST_DEBUG_OBJECT (v4l2object->element, "tv_norm=%d, norm=%p",
+      v4l2object->tv_norm, norm);
   if (norm) {
     gst_tuner_set_norm (tuner, norm);
   } else {
     norm =
         GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element)));
     if (norm) {
-      g_free (v4l2object->norm);
-      v4l2object->norm = g_strdup (norm->label);
+      v4l2object->tv_norm =
+          gst_v4l2_tuner_get_std_id_by_norm (v4l2object, norm);
       gst_tuner_norm_changed (tuner, norm);
     }
   }
@@ -1887,13 +1941,15 @@ default_frame_sizes:
     }
 
     /* Since we can't get framerate directly, try to use the current norm */
-    if (v4l2object->norm && v4l2object->norms) {
+    if (v4l2object->tv_norm && v4l2object->norms) {
       GList *norms;
       GstTunerNorm *norm = NULL;
+      GstTunerNorm *current =
+          gst_v4l2_tuner_get_norm_by_std_id (v4l2object, v4l2object->tv_norm);
 
       for (norms = v4l2object->norms; norms != NULL; norms = norms->next) {
         norm = (GstTunerNorm *) norms->data;
-        if (!strcmp (norm->label, v4l2object->norm))
+        if (!strcmp (norm->label, current->label))
           break;
       }
       /* If it's possible, set framerate to that (discrete) value */
index a0dd41c..a7b590d 100644 (file)
@@ -108,7 +108,7 @@ struct _GstV4l2Object {
   GList *channels;
 
   /* properties */
-  gchar *norm;
+  v4l2_std_id tv_norm;
   gchar *channel;
   gulong frequency;
 
@@ -133,11 +133,12 @@ GType gst_v4l2_object_get_type (void);
     PROP_DEVICE,                       \
     PROP_DEVICE_NAME,                  \
     PROP_DEVICE_FD,                    \
-    PROP_FLAGS,                        \
+    PROP_FLAGS,                         \
     PROP_BRIGHTNESS,                   \
     PROP_CONTRAST,                     \
     PROP_SATURATION,                   \
-    PROP_HUE
+    PROP_HUE,                           \
+    PROP_TV_NORM
 
 /* create/destroy */
 GstV4l2Object *        gst_v4l2_object_new              (GstElement * element,
index fcf7e87..1c8108b 100644 (file)
@@ -55,6 +55,7 @@
 
 
 #include "gstv4l2colorbalance.h"
+#include "gstv4l2tuner.h"
 #ifdef HAVE_XVIDEO
 #include "gstv4l2xoverlay.h"
 #endif
@@ -91,6 +92,7 @@ enum
 
 GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SinkClass, gst_v4l2sink);
 GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Sink, gst_v4l2sink);
+GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Sink, gst_v4l2sink);
 #ifdef HAVE_XVIDEO
 GST_IMPLEMENT_V4L2_XOVERLAY_METHODS (GstV4l2Sink, gst_v4l2sink);
 #endif
@@ -105,10 +107,10 @@ gst_v4l2sink_iface_supported (GstImplementsInterface * iface, GType iface_type)
   g_assert (iface_type == GST_TYPE_X_OVERLAY ||
       iface_type == GST_TYPE_NAVIGATION ||
       iface_type == GST_TYPE_COLOR_BALANCE ||
-      iface_type == GST_TYPE_VIDEO_ORIENTATION);
+      iface_type == GST_TYPE_VIDEO_ORIENTATION || iface_type == GST_TYPE_TUNER);
 #else
   g_assert (iface_type == GST_TYPE_COLOR_BALANCE ||
-      iface_type == GST_TYPE_VIDEO_ORIENTATION);
+      iface_type == GST_TYPE_VIDEO_ORIENTATION || iface_type == GST_TYPE_TUNER);
 #endif
 
   if (v4l2object->video_fd == -1)
@@ -151,6 +153,11 @@ gst_v4l2sink_init_interfaces (GType type)
     NULL,
     NULL,
   };
+  static const GInterfaceInfo v4l2_tuner_info = {
+    (GInterfaceInitFunc) gst_v4l2sink_tuner_interface_init,
+    NULL,
+    NULL,
+  };
 #ifdef HAVE_XVIDEO
   static const GInterfaceInfo v4l2_xoverlay_info = {
     (GInterfaceInitFunc) gst_v4l2sink_xoverlay_interface_init,
@@ -181,6 +188,7 @@ gst_v4l2sink_init_interfaces (GType type)
 
   g_type_add_interface_static (type,
       GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info);
+  g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info);
 #ifdef HAVE_XVIDEO
   g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info);
   g_type_add_interface_static (type,
index c5f8442..a805396 100644 (file)
@@ -237,7 +237,6 @@ gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm)
 GstTunerNorm *
 gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object)
 {
-  GList *item;
   v4l2_std_id norm;
 
   /* assert that we're opened and that we're using a known item */
@@ -245,6 +244,14 @@ gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object)
 
   gst_v4l2_get_norm (v4l2object, &norm);
 
+  return gst_v4l2_tuner_get_norm_by_std_id (v4l2object, norm);
+}
+
+GstTunerNorm *
+gst_v4l2_tuner_get_norm_by_std_id (GstV4l2Object * v4l2object, v4l2_std_id norm)
+{
+  GList *item;
+
   for (item = v4l2object->norms; item != NULL; item = item->next) {
     if (norm & GST_V4L2_TUNER_NORM (item->data)->index)
       return (GstTunerNorm *) item->data;
@@ -253,6 +260,20 @@ gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object)
   return NULL;
 }
 
+v4l2_std_id
+gst_v4l2_tuner_get_std_id_by_norm (GstV4l2Object * v4l2object,
+    GstTunerNorm * norm)
+{
+  GList *item;
+
+  for (item = v4l2object->norms; item != NULL; item = item->next) {
+    if (norm == GST_TUNER_NORM (item->data))
+      return GST_V4L2_TUNER_NORM (item->data)->index;
+  }
+
+  return 0;
+}
+
 void
 gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object,
     GstTunerChannel * channel, gulong frequency)
index bf9ff94..699ca87 100644 (file)
@@ -94,6 +94,11 @@ void              gst_v4l2_tuner_set_norm_and_notify      (GstV4l2Object * v4l2o
 GstTunerNorm*     gst_v4l2_tuner_get_norm                 (GstV4l2Object * v4l2object);
 gboolean          gst_v4l2_tuner_set_norm                 (GstV4l2Object * v4l2object,
                                                           GstTunerNorm * norm);
+GstTunerNorm*     gst_v4l2_tuner_get_norm_by_std_id       (GstV4l2Object * v4l2object,
+                                               v4l2_std_id norm);
+v4l2_std_id       gst_v4l2_tuner_get_std_id_by_norm       (GstV4l2Object * v4l2object,
+                                               GstTunerNorm * norm);
+
 /* frequency */
 void              gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object,
                                                            GstTunerChannel * channel, 
index e9d3069..3808d8e 100644 (file)
@@ -229,6 +229,9 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
         standard.frameperiod.denominator, standard.frameperiod.numerator);
     v4l2norm->index = standard.id;
 
+    GST_DEBUG_OBJECT (v4l2object->element, "index=%08x, label=%s",
+        (unsigned int) v4l2norm->index, norm->label);
+
     v4l2object->norms = g_list_prepend (v4l2object->norms, (gpointer) norm);
   }
   v4l2object->norms = g_list_reverse (v4l2object->norms);